学习总结

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

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

打印结果:

a=0x7fff38352af0

a[0]=0x7fff38352af0

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

  1. #include <stdio.h>
  2. int main(){
  3. int a[]={,},*p;
  4. p=a;
  5. printf("&a=%p\n",&a);
  6. printf("p=%p\n",p);
  7. printf("a=%d\n",*a);
  8. printf("p=%d\n",*p);
  9. printf("---------------\n");
  10. printf("a=%p\n",(a+));
  11. printf("a=%d\n",*(a+));
  12. p++;
  13. printf("p=%p\n",p);
  14. printf("p=%d\n",*p);
  15. return ;
  16. }

打印结果:

&a=0x7fffa1a350a0

p=0x7fffa1a350a0

a=1

p=1

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

a=0x7fffa1a350a4

a=2

p=0x7fffa1a350a4

p=2

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

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

  1. #include <stdio.h>
  2.  
  3. int main(){
  4. int urn[]={,,,,};
  5. int *ptr1,*ptr2,*ptr3,*ptr4;
  6.  
  7. printf("指针赋值\n");
  8. ptr1 = urn;
  9. printf("ptr1=%p\n",ptr1);
  10. ptr2 = &urn[];
  11. printf("ptr2=%p\n",ptr2);
  12.  
  13. printf("指针求值或取值\n");
  14. printf("(int)ptr1=%d\n",*ptr1);
  15. printf("(int)ptr2=%d\n",*ptr2);
  16.  
  17. printf("取指针地址\n");
  18. printf("&ptr1=%p\n",&ptr1);
  19. printf("&ptr2=%p\n",&ptr2);
  20.  
  21. printf("将一个整数加给指针或增加指针的值\n");
  22. ptr1++;
  23. printf("ptr1=%p\n",ptr1);
  24. printf("(int)ptr1=%d\n",*ptr1);
  25.  
  26. printf("从指针中减去一个整数或减少指针的值\n");
  27. ptr2--;
  28. printf("ptr2=%p\n",ptr2);
  29. printf("(int)ptr2=%d\n",*ptr2);
  30.  
  31. printf("求差值");
  32. ptr3 = &urn[];
  33. ptr4 = &urn[];
  34. printf("ptr4-ptr3=%d\n",ptr4-ptr3);
  35.  
  36. printf("比较两个指针本身的值(非指针指向数据的值)");
  37. printf("ptr4>ptt3=%d\n",ptr4>ptr3);
  38.  
  39. return ;
  40. }

运行结果:

指针赋值

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)

  1. #include <stdio.h>
  2.  
  3. int main(){
  4. double d[][];
  5. int i;
  6. double sum1,sum2,sum3,maxDouble;
  7. printf("enter 5 double for first doubleArr:\n");
  8. for(i=;i<;i++){
  9. scanf("%lf",&d[][i]);
  10. }
  11.  
  12. printf("enter 5 double for second doubleArr:\n");
  13. for(i=;i<;i++){
  14. scanf("%lf",&d[][i]);
  15. }
  16.  
  17. printf("enter 5 double for third doubleArr:\n");
  18. for(i=;i<;i++){
  19. scanf("%lf",&d[][i]);
  20. }
  21.  
  22. printf("thank you for your scanf.\n\n");
  23.  
  24. sum1=;
  25. for(i=;i<;i++){
  26. sum1+=d[][i];
  27. if(i==)
  28. maxDouble=d[][];
  29. if(d[][i]>maxDouble)
  30. maxDouble=d[][i];
  31. }
  32. printf("average value of first doubleArr is %f\n",sum1/);
  33.  
  34. sum2=;
  35. for(i=;i<;i++){
  36. sum2+=d[][i];
  37. if(d[][i]>maxDouble)
  38. maxDouble=d[][i];
  39. }
  40. printf("average value of second doubleArr is %f\n",sum2/);
  41.  
  42. sum3=;
  43. for(i=;i<;i++){
  44. sum3+=d[][i];
  45. if(d[][i]>maxDouble)
  46. maxDouble=d[][i];
  47. }
  48. printf("average value of third doubleArr is %f\n",sum3/);
  49.  
  50. printf("average value of all double data is %f\n",(sum1+sum2+sum3)/);
  51. printf("the max double is %f\n",maxDouble);
  52.  
  53. return ;
  54. }

运行结果:

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. java socket 网络编程常见异常

    1.java.net.SocketTimeoutException 这个异常比较常见,socket超时.一般有2个地方会抛出这个,一个是connect的时候,这个超时参数由connect(Socket ...

  2. H5学习系列之文件读取API--本文转自http://blog.csdn.net/jackfrued/article/details/8967667

    HTML5定义了FileReader作为文件API的重要成员用于读取文件,根据W3C的定义,FileReader接口提供了读取文件的方法和包含读取结果的事件模型. FileReader的使用方式非常简 ...

  3. 关于fast cgi和php-fpm的关系

    相关文档“https://segmentfault.com/q/1010000000256516%20” 一.什么是cgi cgi是一个协议,这个协议规定我们web服务器访问的时候,nginx和php ...

  4. Web程序的运行原理及流程(二)

    其实WEB服务器和WEB应用服务器这两个概念特别容易混淆  可以理解为装了不同软件(服务)的两台计算机(服务器)吧 先对两个概念做一个简单介绍 了解了基本的概念 我们再用两个典型的例子做一下比较(建立 ...

  5. 1074. Reversing Linked List (25)

    模拟题,注意当k == 1 与 k == n时情况 #include <stdio.h> #include <string.h> #include <iostream&g ...

  6. IE WebBrowser事件触发

    <= IE6: IE6 下如果iframe很多,子框架的BeforeNavigate2,DownloadBegin,DownloadComplete,DocumentComplete可能交替出现 ...

  7. Balance - 七夕悠然

    想争取一个月至少一篇博客的,还是没搭上七月的末班车.两个小妹妹来上海看我了,工作上又有点儿忙,充分利用所有时间了,还是没有挪出时间来写东西,貌似写东西也要时机一样,需要在可以静静思考的时候,再加上有淡 ...

  8. 两种状态显示处理. enum , Linq AsEnumerable

    1.ENUM protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { GridViewRow ro ...

  9. vagrant 基本配置

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

  10. IAR FOR ARM的安装及破解

    本博文主要是介绍如何安装以及破解IAR FOR ARM . 1.下载IAR FOR ARM以及注册机 IAR FOR ARM下载:http://pan.baidu.com/s/1i5t1qF7 注册机 ...