学习总结

1、数组初始化方式:

int a[]={1,2,3}

int a[SIZE]={1,2,3} //SIZE是宏定义,数组初始化个数不能大于SIZE,否则报错;当个数小

//SIZE,自动补0;只定义不初始化,默认值是当前存储单元中已有的数值。

int a[SIZE/不定长]={1,[3],2} //C99支持通过[int]=x来定义具体位置值,跳过的默认值为0。

2、通过const修饰的数组为只读数组,数组的每个元素当成常量来处理,如:

const int a[2]={1,2};

const int b[2];

a[1]=3; //编译不通过,无法修改,已有值2;

b[1]=3; //编译不通过,无法修改,已有默认存储单元数值。

3、数组赋值方式:

int a[]={1,2,3}; //允许

int a[2];a[1]=2; //允许

int a[2]={1,2};int b[2];b=a //不允许

int a[2];a[2]={1,2}; //不起作用

4、数据边界问题:数组的计数器是从0开始的,在标准C中,编译器是不会检查索引的合法性,因为C认为编译器在运行时逐个检查每个索引的合法代码会导致程序运行速度变慢,因此C会认为程序员的代码是正确的,但C太天真了,事情没有完美的,肯定存在人为出错因素,因此问题就产生了。不同编译器对于这种问题会出现不同的错误,所以要特别注意。

5、指定数组大小在C99之前是不允许通过变量定义,如

int n=2;

a[n]={1,2}; //C99前不允许,C99允许

6、二维数组初始化:

int a[2][3]={1,2,3,4,5,6}

int a[2][3]={{1,2,3},{4,5,6}}

按照二维表格排布,2相当于行数,3相当于列数。如a[2][3]={1,2,3,4,5,6}布局如下:

1 2 3

4 5 6

如a[3][2]={1,23,4,5,6}布局如下:

1 2

3 4

5 6

7、指针提供了一种用来使用地址的符号方法。由于计算机的硬件指令很大程度上依赖于地址,所以指针能够类似于计算机底层的表达,使工作更加高效。特别的,指针能够很有效的处理数组,数据实际上是一种变相使用指针的形式:

#include <stdio.h>
int main(){
int a[]={,};
printf("a=%p\n",a);
printf("a[0]=%p\n",&a[]);
return ;
}

打印结果:

a=0x7fff38352af0

a[0]=0x7fff38352af0

其实,数组名是该数组首元素的地址。

 #include <stdio.h>
int main(){
int a[]={,},*p;
p=a;
printf("&a=%p\n",&a);
printf("p=%p\n",p);
printf("a=%d\n",*a);
printf("p=%d\n",*p);
printf("---------------\n");
printf("a=%p\n",(a+));
printf("a=%d\n",*(a+));
p++;
printf("p=%p\n",p);
printf("p=%d\n",*p);
return ;
}

打印结果:

&a=0x7fffa1a350a0

p=0x7fffa1a350a0

a=1

p=1

---------------

a=0x7fffa1a350a4

a=2

p=0x7fffa1a350a4

p=2

从以上程序可以看出,数组指针加1,并非指针地址值加1,而是指向数组下一个元素的地址。

8、指针的基本操作:赋值、求值或取值、取指针地址、将一个整数加给指针、增加指针的值、从指针中减去一个整数、减小指针的值、求差值、比较。

 #include <stdio.h>

 int main(){
int urn[]={,,,,};
int *ptr1,*ptr2,*ptr3,*ptr4; printf("指针赋值\n");
ptr1 = urn;
printf("ptr1=%p\n",ptr1);
ptr2 = &urn[];
printf("ptr2=%p\n",ptr2); printf("指针求值或取值\n");
printf("(int)ptr1=%d\n",*ptr1);
printf("(int)ptr2=%d\n",*ptr2); printf("取指针地址\n");
printf("&ptr1=%p\n",&ptr1);
printf("&ptr2=%p\n",&ptr2); printf("将一个整数加给指针或增加指针的值\n");
ptr1++;
printf("ptr1=%p\n",ptr1);
printf("(int)ptr1=%d\n",*ptr1); printf("从指针中减去一个整数或减少指针的值\n");
ptr2--;
printf("ptr2=%p\n",ptr2);
printf("(int)ptr2=%d\n",*ptr2); printf("求差值");
ptr3 = &urn[];
ptr4 = &urn[];
printf("ptr4-ptr3=%d\n",ptr4-ptr3); printf("比较两个指针本身的值(非指针指向数据的值)");
printf("ptr4>ptt3=%d\n",ptr4>ptr3); return ;
}

运行结果:

指针赋值

ptr1=0x7fff886c8570

ptr2=0x7fff886c8578

指针求值或取值

(int)ptr1=100

(int)ptr2=300

取指针地址

&ptr1=0x7fff886c8568

&ptr2=0x7fff886c8560

将一个整数加给指针或增加指针的值

ptr1=0x7fff886c8574

(int)ptr1=200

从指针中减去一个整数或减少指针的值

ptr2=0x7fff886c8574

(int)ptr2=200

求差值

ptr4-ptr3=3

比较两个指针本身的值(非指针指向数据的值)

ptr4>ptt3=1

9、函数形参为数组时,一般是通过传递指针,如果是使用数组形参,那么函数中必须分配足够存放一份原数组拷贝的存储空间。为了避免函数不对原数组进行修改,可以通过const关键字对形参进行修饰,需要理解的是这样使用const并不要求原始数组固定不变的;这只是说明函数在处理数据时,应把数组当作是固定不变的。使用const可以对数组提供保护,就像值传递可以对基本类型提供保护一样。

int sum(int ar[],int n) //可以修改数组

int sum(const int ar[],int n) //不可修改数组

10、前面学习过可以使用const关键字来创建符号常量(const int PI=3.14159;),也可以是用#defined PI 3.15159来定义,但使用const还可以创建数组常量、指针常量以及指向常量的指针,使用const关键在于修饰的对象,修饰的对象不一样,效果也不同。

场景1:修饰数组

const int a[]={1,2,3,4,5};  //整个数组为常量数组,不可以修改。

a[0]=10;  //不允许

a[1]=11;  //不允许

场景2:修饰常量指针(指向常量的指针,常量为形容词,指针为名词,这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针)

int a[]={1,2,3,4,5};

const int *p=a;   //p指向数组的开始处

p[0]=10;  //不允许,因为指针指向常量,所以不能通过指针修改

a[0]=10;  //允许,但能通过数组本身修改,因为数组本身不是常量(特别注意)

场景3:修饰指针常量(指针是形容词,常量是名词。这回是以常量为中心的一个偏正结构短语。那么,指针常量的本质是一个常量,而用指针修饰它,那么说明这个常量的值应该是一个指针)

int a[]={1,2,3,4,5};

int * const p=a;

p[0]=10; //允许,数组非常量数组

p++;    //不允许,p为常量,不允许修改

p=&a[3]; //不允许,p为常量,不允许修改

11、二维数组a[4][2],其中a为数组首元素的地址,在本例中a首元素本身又是包含两个int的数组,如下所示:

a[0][0]=11=0x7fff908c0c60 a[0][1]=12=0x7fff908c0c64

a[1][0]=21=0x7fff908c0c68 a[1][1]=22=0x7fff908c0c6c

a[2][0]=31=0x7fff908c0c70 a[2][1]=32=0x7fff908c0c74

a[3][0]=41=0x7fff908c0c78 a[3][1]=42=0x7fff908c0c7c

a=0x7fff908c0c60         //二维数组首地址,a指向的对象是一个int数组(这里是两个int)

*a=0x7fff908c0c60        //*a就是一个int数组,跟a指向的是同一个int元素

*a+1=0x7fff0f1eebb4      //*a指向对象是一个int元素,加1就是向当前递增一个int

a+2=0x7fff908c0c70       //a指向的是一个int数组,加2就是向前地址两个int数组

*(a+2)=0x7fff908c0c70     //先是a向前地址两个int数组,再指向当前一维数组的首地址

*(a+2)+1=0x7fff908c0c74   //同*a

*(*(a+2)+1)=32           //取出上面地址的值

12、数组指针和指针数组的区别(参考百度网友解析):

int a[3][4]这个无需多说,就是一个二维数组。

int (*p)[4]就相当于int p[][4],它就是一个二维数组的指针,可以指向一个第二维度为4的二维数组。而a就是这样的数组,因而下面是合法的。

p=a;

int *p[3]是指针数组。说白了,就是定义了三个指针,分别为p[0],p[1],p[2]。可以将他们单独拿来使用。

int a1,a2,a3;

p[0]=&a1;

p[1]=&a2;

p[2]=&a3;

13、相对于数值类型的赋值,指针之间的赋值会更加的严格:

int n=5;

int *pi;

double x;

double pd;

x=n; //通过

pd=pi; //不通过

-------------------------例子分割线------------------------------------

int *pt;

int (*pa)[3];

int ar1[2][3];

int ar2[3][2];

int **p2;

pt = &ar1[0][0]; //pt是指向整数的指针,&a[0][0]也是指向整数的指针,所以合法

pt = ar1[0];    //ar1[0]同样是指向整数的指针,所以合法

pt = ar1;      // ar1是一个指向包含3位int数组的指针,和pt不一样,所以不合法

pa = ar1;      //pa是一个指向包含3位int数组的指针,和ar1一样,所以合法。

pa = ar2;      //ar2是一个指向包含2位int数组的指针,和pa不一样, 所以不合法

p2 = &pt;     //p2是指向整数指针的指针,pt是指向整数的指针,所以&pt与p2类型相同

*p2 = ar2[0];  //*p2是指向整数的指针,而ar2[0]同样是指向整数的指针,所以合法

P2 = ar2;     //ar2是指向一个包含2位int数组的指针,与P2不一样,所以不合法。

-------------------------例子分割线------------------------------------

int *p1;

const int *p2;

const int **pp2;

p1 = p2;    //非法把const指针赋值给非const指针

p2 = p1;    //合法把非const指针赋值给const指针

pp2= &p1;  //非法通过两层运算吧非const指针赋值给const指针,这样会引起赋值不安全详见P271例子。

14、编程题(题12)

 #include <stdio.h>

 int main(){
double d[][];
int i;
double sum1,sum2,sum3,maxDouble;
printf("enter 5 double for first doubleArr:\n");
for(i=;i<;i++){
scanf("%lf",&d[][i]);
} printf("enter 5 double for second doubleArr:\n");
for(i=;i<;i++){
scanf("%lf",&d[][i]);
} printf("enter 5 double for third doubleArr:\n");
for(i=;i<;i++){
scanf("%lf",&d[][i]);
} printf("thank you for your scanf.\n\n"); sum1=;
for(i=;i<;i++){
sum1+=d[][i];
if(i==)
maxDouble=d[][];
if(d[][i]>maxDouble)
maxDouble=d[][i];
}
printf("average value of first doubleArr is %f\n",sum1/); sum2=;
for(i=;i<;i++){
sum2+=d[][i];
if(d[][i]>maxDouble)
maxDouble=d[][i];
}
printf("average value of second doubleArr is %f\n",sum2/); sum3=;
for(i=;i<;i++){
sum3+=d[][i];
if(d[][i]>maxDouble)
maxDouble=d[][i];
}
printf("average value of third doubleArr is %f\n",sum3/); printf("average value of all double data is %f\n",(sum1+sum2+sum3)/);
printf("the max double is %f\n",maxDouble); return ;
}

运行结果:

enter 5 double for first doubleArr:

11

12

13

14

15

enter 5 double for second doubleArr:

21

22

23

24

25

enter 5 double for third doubleArr:

31

32

33

34

35

thank you for your scanf.

average value of first doubleArr is 13.000000

average value of second doubleArr is 23.000000

average value of third doubleArr is 33.000000

average value of all double data is 115.000000

the max double is 35.000000

【C语言学习】《C Primer Plus》第10章 数组和指针的更多相关文章

  1. C Primer Plus 第10章 数组和指针 编程练习

    这章感觉好难啊,放个别人的总结. // 多维数组和指针 #include <stdio.h> int main(void) { int zippo[4][2] = {{2, 4}, {6, ...

  2. 12天学好C语言——记录我的C语言学习之路(Day 10)

    12天学好C语言--记录我的C语言学习之路 Day 10: 接着昨天的指针部分学习,有这么一个题目: //还是四个学生,四门成绩,只要有学生一门功课没及格就输出这个学生的所有成绩 /*//progra ...

  3. 《Go语言实战》笔记之第四章 ----数组、切片、映射

    原文地址: http://www.niu12.com/article/11 ####数组 数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块. 数组存储的类型可以是内置类型,如整型 ...

  4. C++ Primer高速入门之六:数组和指针

    更新:勘误,delete [] 猪 我们知道,C语言以及早期的面向结构的语言差点儿都支持数组定义.比方整形数组int 女神[2].表示有俩数: 女神[0], 女神[1].她们都是整数. C++ 语言为 ...

  5. Java程序设计基础笔记 • 【第10章 数组】

    全部章节   >>>> 本章目录 10.1 数组概述 10.1.1 数组优势 10.1.2 Java中的数组 10.1.3 数组的分类 10.2 一维数组 10.2.1 数组的 ...

  6. C Primer Plus_第10章_数组和指针_编程练习

    1. /*rain.c 针对若干年的降水量数据,计算年降水总量.年降水平均量,以及月降水平均量*/ #include <stdio.h> #define MONTHS 12 #define ...

  7. 《C++ primer》--第10章

    习题10.21 解释map和set容器的差别,以及他们各自适用的情况. 解答: map容器和set容器的差别在于: map容器是键-值对的集合,而set容器只是键的集合: map类型适用于需要了解键与 ...

  8. C++ Primer 5th 第10章 泛型算法

    练习10.1:头文件algorithm中定义了一个名为count的函数,它类似find,接受一对迭代器和一个值作为参数.count返回给定值在序列中出现的次数.编写程序,读取int序列存入vector ...

  9. [C++ Primer Plus] 第10章、对象和类(一)程序清单——辨析三个const

    程序清单10.1+10.2+10.3 头文件stock.h #ifndef STOCK00_H_ //先测试x是否被宏定义过 #define STOCK00_H_ //如果没有宏定义,就宏定义x并编译 ...

随机推荐

  1. Faster-RCNN 解析

    http://blog.csdn.net/xzzppp/article/details/52317863 包含faster-rcnn源码和对应的训练测试相关的知识点解析

  2. 使用 VisualCode + iTerm2 提交github的Pull Request

    VisualCode集成github功能,是程序猿参与开源项目的利器.相比Sublime简单了很多(插件安装繁琐,比如你试试在Sublime2 安装gosublime,这里有坑; Sublime 3修 ...

  3. GIL与线程互斥锁

    GIL 是解释器级别的锁,是限制只有一个原生线程运行,防止多个原生线程之间修改底层的共享数据.而线程互斥锁是防止多个线程同时修改python内存空间的共享数据.

  4. Groovy 转换JSON和生产JSON

    Groovy 类和JSON之间的相互转换,主要在groovy.json包下面 1. JsonSlurper JsonSlurper 这个类用于转换JSON文本或从Groovy 数据结构中读取内容例如m ...

  5. 转载:java 中对类中的属性使用set/get方法的意义和用法

    经常看到有朋友提到类似:对类中的属性使用set/get方法的作用?理论的回答当然是封闭性之类的,但是这样对我们有什么作用呢?为什么要这样设计?我直接使用属性名来访问不是更直接,代码更简洁明了吗?下面我 ...

  6. python day2 列表的常用操作方法

    #创建列表方法一li = ['aa','bb','cc']方法二li = list(['aa','bb','cc'])print(li)返回 ['aa', 'bb', 'cc']----------- ...

  7. 【Java】使用iText生成PDF文件

    iText介绍 iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转 ...

  8. linux系统编程之I/O内核数据结构

    文件在内核中是用三种数据结构进行表示的 (1)文件描述符表:文件描述符表是一个结构体数组,数组的下标就是open函数返回的文件描述符. 文件描述符表的每一个记录有两个字段   *文件描述符标志 * 文 ...

  9. vagrant 基本配置

    首先安装好virtualbox,可以对照官网教程 https://www.if-not-true-then-false.com/2010/install-virtualbox-with-yum-on- ...

  10. js如何判断手机机型

    <script language="javascript"> window.onload = function () { alert("1"); v ...