【C语言学习】《C Primer Plus》第10章 数组和指针

时间:2022-09-24 14:58:22

学习总结

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&plus;&plus; 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&lowbar;第10章&lowbar;数组和指针&lowbar;编程练习

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

  7. 《C&plus;&plus; primer》--第10章

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

  8. C&plus;&plus; Primer 5th 第10章 泛型算法

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

  9. &lbrack;C&plus;&plus; Primer Plus&rsqb; 第10章、对象和类(一)程序清单——辨析三个const

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

随机推荐

  1. HTTP请求与响应方式

    HTTP请求格式 当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息,HTTP请求信息由3部分组成: l   请求方法URI协议/版本 l   请求头(Request Hea ...

  2. C&num;中一个关于不同窗体间的颜色参数的传递

    1目标是 在弹出菜单中选择颜色,在主菜单中对控件进行操作(弹出菜单选择的颜色就是主菜单控件的颜色) 2颜色属性需要来回转换(也许不用转换,暂时还不会,有会的提醒下,TKS) 3用到一个颜色控件(col ...

  3. 【java】之转码

    GBK->UTF-8 String str = "任意字符串"; str = new String(str.getBytes("gbk"),"u ...

  4. C&num;中winform窗体如何嵌入cmd命令窗口

    解决方法一: 自己放一个文本框,改成黑色,然后输入命令,执行时,你Process.Start cmd ,此时CMD窗口不显示,然后,将CMD的返回值,再取出来,设回文本框. 如何用这种方法实时获取cm ...

  5. 五、C&num; 类

    面向对象编程 类是面向对象编程的3个主要特征---封装.继承和多态性---的基础.   封装允许隐藏细节.   继承 继承关系至少涉及两个类,其中一个类(基类)是另一个类的更泛化的版本.   为了从一 ...

  6. (转)jQuery插件开发全解析

    jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...

  7. Binlog的三个业务应用场景

    1.什么是binlog binlog是mysql的一种二进制日志文件,用来记录数据的变化.mysql使用binlog进行主从复制,如图: 客户端向master的mysql sever写入数据 当数据发 ...

  8. json和数组的区别

    原文地址:https://www.cnblogs.com/zhangjingyun/p/4554054.html 我们都知道,json和数组一样,都可以存数据,但是下面我们来总结一下json和数组的区 ...

  9. c&plus;&plus;11の的左值、右值以及move,foward

    左值和右值的定义 在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值.有些变量既可以当左值又可以当右值.进一步来讲,左值为Lvalue,其实L代表Location,表示在内存 ...

  10. 三张图搞懂JavaScript的原型对象与原型链 &sol; js继承,各种继承的优缺点(原型链继承,组合继承,寄生组合继承)

    摘自:https://www.cnblogs.com/shuiyi/p/5305435.html 对于新人来说,JavaScript的原型是一个很让人头疼的事情,一来prototype容易与__pro ...