• 《C语言程序设计 第4版》笔记和代码 第十一章 指针和数组


    第十一章 指针和数组

    11.1 指针和一维数组间的关系

    1 由于数组名代表数组元素的连续存储空间的首地址,因此,数组元素既可以用下标法也可以用指针来引用。

    例11.1见文末

    2 p+1p++在本质上是两个不同的操作,前者不改变当前指针的指向(因为没有进行赋值操作),而后者相当于执行p=p+sizeof(p的基类型),因此改变了p指针的指向,指向下一个元素。

    3 p++不是将指针变量加1字节,而是加上1*sizeof(基类型)个字节。

    4 输入p和a都是表示首地址,但是数组名a是一个指针常量不可以进行增1或减1操作,而指针p是一个指针变量可以这种操作。

    5 用一维数组作函数形参与指针变量作函数形参在本质上都是一样的,因此在被调函数中既能以下标形式也能以指针形式访问元素。

    例11.2见文末

    11.2 指针和二维数组间的关系

    1 如数组:int a[M][N] 可在逻辑上看成一个M行N列的存储空间。

    2 可将二维数组看成由多个元素组成的一维数组,因此可以通过行地址列地址定位到每个具体的元素。

    3 类似于行地址和列地址,可以用行指针列指针来定位具体元素。

    例11.3见文末

    11.3 指针数组及其应用

    1 指针数组是值由若干个基类型相同的指针组成的数组。定义形式为:

    类型关键字 *指针数组名[数量];

    2 指针数组可以用存储多个字符串

    例11.4见文末

    3 指针数组的元素是一个指针,因此与指针变量一样,在使用指针数组前必须对数组元素进行初始化

    4 指针数组可用于表示命令行参数

    例11.5见文末

    11.4 动态数组

    1 一个编译后的C程序会获得4块在逻辑上不相同并且用于不同目的的内存储区。

    2 从低端起,第一块内存为只读存储区,用于存放程序的机器代码和字符串字面量等只读数据。

    3 第一块内存相邻的一块是静态存储区,用于存放程序中的全局变量和静态变量等。

    4 其他两块内存分别称为,属于动态存储区

    5 用于保存函数调用时的返回地址、函数的形参、局部变量及CPU的当前状态等程序的运行信息;是一个自由存储区,程序可以用C的动态分配函数来使用堆。

    6 变量的内存分配可以通过:(1)从静态存储区分配;(2)在上分配;(3)在上分配。

    7 指针的另外一个作用是通过与动态内存分配函数联用,使动态数组成为可能。

    8 动态内存分配是指程序运行时为变量分配内存的一种方法,在上实现。需要添加头文件

    9 函数malloc()用于分配若干字节的内存空间,返回一个指向该内存首地址的指针。如果系统不能提供足够的内存单元,函数则会返回一个空指针NULL。

    10 malloc()函数的使用举例:

    pi=(int *)malloc(sizeof(int));

    表明向系统申请一个大小为4字节的内存,并且pi为int型指针。

    11 函数calloc()可用于给若干同一类型的数据项分配连续的存储空间并赋值为0,因此calloc()比malloc()更安全。

    12 函数free()的功能是释放向系统动态申请的由指针p指向的存储空间。该函数的形参只能是由malloc()或calloc()申请内存时返回的地址。

    13 函数realloc()用于改变原来分配的存储空间的大小。

    例11.6见文末

    14 永远不要忘记用free()释放不再使用的动态申请的内存。

    例11.7见文末

    代码

    11.1a

    演示数组元素的引用方法,下标法

    1. //例11.1a 演示数组元素的引用方法,下标法
    2. #include
    3. int main(void)
    4. {
    5. int a[5],i;
    6. printf("Input five numbers:");
    7. for(i=0;i<5;i++)
    8. {
    9. scanf("%d",&a[i]);
    10. }
    11. for(i=0;i<5;i++)
    12. {
    13. printf("%4d",a[i]);//通过数组下标,一个个将元素打印出来
    14. }
    15. printf("\n");
    16. return 0;
    17. }

    11.1b

    演示数组元素的引用方法,解引用 

    1. //例11.1b 演示数组元素的引用方法,解引用
    2. #include
    3. int main(void)
    4. {
    5. int a[5],i;
    6. printf("Input five numbers:");
    7. for(i=0;i<5;i++)
    8. {
    9. scanf("%d",a+i);//a+i等价于&a[i]
    10. }
    11. for(i=0;i<5;i++)
    12. {
    13. printf("%4d",*(a+i));//等价于a[i]
    14. }
    15. printf("\n");//这种方法是效率最高的
    16. return 0;
    17. }

     11.1c

    演示数组元素的引用方法,用移动指针变量p的方法 

    1. //例11.1c 演示数组元素的引用方法,用移动指针变量p的方法
    2. #include
    3. int main(void)
    4. {
    5. int a[5],*p;
    6. printf("Input five numbers:");
    7. for(p=a;p5;p++)
    8. {
    9. scanf("%d",p);//指针法输入
    10. }
    11. for(p=a;p5;p++)
    12. {
    13. printf("%4d",*p);//指针法输出
    14. }
    15. printf("\n");
    16. return 0;
    17. }

    11.1d

    演示数组元素的引用方法,用移动指针结合下标的方法 

    1. //例11.1d 演示数组元素的引用方法,用移动指针结合下标的方法
    2. #include
    3. int main(void)
    4. {
    5. int a[5],*p=NULL,i;//需要初始化指针
    6. printf("Input five numbers:");
    7. p=a;//等价于p=&a[0];
    8. for(i=0;i<5;i++)
    9. {
    10. scanf("%d",&p[i]);//指针法输入
    11. }
    12. for(i=0;i<5;i++)
    13. {
    14. printf("%4d",p[i]);//指针法输出
    15. }
    16. printf("\n");
    17. return 0;
    18. }

    11.2主函数a

    主函数a 演示数组和指针变量作为函数参数,实现与例11.1相同的功能

    1. //例11.2 主函数a 演示数组和指针变量作为函数参数,实现与例11.1相同的功能
    2. #include
    3. int main(void)
    4. {
    5. int a[5];
    6. printf("Input five numbers:");
    7. InputArray(a,5);//数组名作函数参数
    8. OutputArray(a,5);
    9. return 0;
    10. }

    11.2 主函数b

    主函数b(实际意义不大) 演示数组和指针变量作为函数参数,实现与例11.1相同的功能

    1. //例11.2 主函数b(实际意义不大) 演示数组和指针变量作为函数参数,实现与例11.1相同的功能
    2. #include
    3. int main(void)
    4. {
    5. int a[5];
    6. int *p=a;
    7. printf("Input five numbers:");
    8. InputArray(p,5);//指针作函数参数
    9. OutputArray(p,5);
    10. return 0;
    11. }

    11.2 几类被调函数

    1. //被调函数实现方法一:形参和访问都用数组
    2. void InputArray(int a[],int n);
    3. void OutputArray(int a[],int n);
    4. void InputArray(int a[],int n)//数组作形参
    5. {
    6. int i;
    7. for(i=0;i
    8. {
    9. scanf("%d",&a[i]);//下标法访问
    10. }
    11. }
    12. void OutputArray(int a[],int n)
    13. {
    14. int i;
    15. for(i=0;i
    16. {
    17. printf("%4d",a[i]);//下标法访问
    18. }
    19. printf("\n");
    20. }
    1. //被调函数实现方法二:形参和访问都用指针
    2. void InputArray(int *pa,int n);
    3. void OutputArray(int *pa,int n);
    4. void InputArray(int *pa,int n)//指针作形参
    5. {
    6. int i;
    7. for(i=0;i//这里指针也需移动
    8. {
    9. scanf("%d",pa);//指针访问
    10. }
    11. }
    12. void OutputArray(int *pa,int n)
    13. {
    14. int i;
    15. for(i=0;i
    16. {
    17. printf("%4d",*pa);//下标法访问
    18. }
    19. printf("\n");
    20. }
    1. //被调函数实现方法三:形参为数组类型,访问用指针法
    2. void InputArray(int a[],int n);
    3. void OutputArray(int a[],int n);
    4. void InputArray(int a[],int n)//指针作形参
    5. {
    6. int i;
    7. for(i=0;i
    8. {
    9. scanf("%d",a+i);//指针访问
    10. }
    11. }
    12. void OutputArray(int a[],int n)
    13. {
    14. int i;
    15. for(i=0;i
    16. {
    17. printf("%4d",*(a+i);//指针访问
    18. }
    19. printf("\n");
    20. }
    1. //被调函数实现方法四:形参用指针变量,访问都用数组方式
    2. void InputArray(int *pa,int n);
    3. void OutputArray(int *pa,int n);
    4. void InputArray(int *pa,int n)//指针作形参
    5. {
    6. int i;
    7. for(i=0;i
    8. {
    9. scanf("%d",&pa[i]);//数组方式访问
    10. }
    11. }
    12. void OutputArray(int *pa,int n)
    13. {
    14. int i;
    15. for(i=0;i
    16. {
    17. printf("%4d",pa[i]);//数组方式访问
    18. }
    19. printf("\n");
    20. }

    11.3a

    编写程序,输入一个3行4列的二维数组,然后输出这个二维数组的元素值。方法一

    1. //例11.3a 编写程序,输入一个3行4列的二维数组,然后输出这个二维数组的元素值。方法一
    2. #include
    3. #define N 4
    4. void InputArray(int p[][N],int m,int n);
    5. void OutputArray(int p[][N],int m,int n);
    6. int main (void)
    7. {
    8. int a[3][4];
    9. printf("Input 3*4 numbers:\n");
    10. InputArray(a,3,4);//向函数传递的是第0行地址
    11. OutputArray(a,3,4);
    12. return 0;
    13. }
    14. void InputArray(int p[][N],int m,int n)
    15. {
    16. int i,j;
    17. for(i=0;i
    18. {
    19. for(j=0;j
    20. {
    21. scanf("%d",&p[i][j]);//使用两层循环就可以完成二维数组的输入
    22. }
    23. }
    24. }
    25. void OutputArray(int p[][N],int m,int n)
    26. {
    27. int i,j;
    28. for(i=0;i
    29. {
    30. for(j=0;j
    31. {
    32. printf("%4d",p[i][j]);//使用两层循环同样可以实现二维数组的打印
    33. }
    34. printf("\n");//在每一个内层循环结束后添加换行符,相当于实现二维数组的逻辑换行
    35. }
    36. }

    11.3b

     编写程序,输入一个3行4列的二维数组,然后输出这个二维数组的元素值。方法二 

    1. //例11.3b 编写程序,输入一个3行4列的二维数组,然后输出这个二维数组的元素值。方法二
    2. #include
    3. #define N 4
    4. void InputArray(int (*p)[N],int m,int n);//不要忘记(*p)
    5. void OutputArray(int (*p)[N],int m,int n);
    6. int main (void)
    7. {
    8. int a[3][4];
    9. printf("Input 3*4 numbers:\n");
    10. InputArray(a,3,4);//向函数传递的是第0行地址
    11. OutputArray(a,3,4);
    12. return 0;
    13. }
    14. void InputArray(int (*p)[N],int m,int n)
    15. {
    16. int i,j;
    17. for(i=0;i
    18. {
    19. for(j=0;j
    20. {
    21. scanf("%d",*(p+i)+j);//相当于先按行移动,再找到对应的列
    22. }
    23. }
    24. }
    25. void OutputArray(int (*p)[N],int m,int n)
    26. {
    27. int i,j;
    28. for(i=0;i
    29. {
    30. for(j=0;j
    31. {
    32. printf("%4d",*(*(p+i)+j));//对*(p+i)+j的解引用
    33. }
    34. printf("\n");//在每一个内层循环结束后添加换行符,相当于实现二维数组的逻辑换行
    35. }
    36. }

    11.3c

    编写程序,输入一个3行4列的二维数组,然后输出这个二维数组的元素值。方法三 

    1. //例11.3c 编写程序,输入一个3行4列的二维数组,然后输出这个二维数组的元素值。方法三
    2. #include
    3. #define N 4
    4. void InputArray(int *p,int m,int n);//不要忘记(*p)
    5. void OutputArray(int *p,int m,int n);
    6. int main (void)
    7. {
    8. int a[3][4];
    9. printf("Input 3*4 numbers:\n");
    10. InputArray(*a,3,4);//注意a前面的*,这个时候先函数传递的就是0行0列的地址,不同于前面传递0行地址
    11. OutputArray(*a,3,4);
    12. return 0;
    13. }
    14. void InputArray(int *p,int m,int n)
    15. {
    16. int i,j;
    17. for(i=0;i
    18. {
    19. for(j=0;j
    20. {
    21. scanf("%d",&p[i*n+j]);//相当于先定位到具体的下标
    22. }
    23. }
    24. }
    25. void OutputArray(int *p,int m,int n)
    26. {
    27. int i,j;
    28. for(i=0;i
    29. {
    30. for(j=0;j
    31. {
    32. printf("%4d",p[n*i+j]);//同样先定位到具体的下标
    33. }
    34. printf("\n");//在每一个内层循环结束后添加换行符,相当于实现二维数组的逻辑换行
    35. }
    36. }

    11.4

    使用指针数组来重新编写例10.4

    1. //例11.4 使用指针数组来重新编写例10.4
    2. #include
    3. #include
    4. #define MAX_LEN 10//字符串的最大长度
    5. #define N 150 //最大参赛国
    6. void SortString(char *ptr[],int n);
    7. int main(void)
    8. {
    9. int i,n;
    10. char name[N][MAX_LEN];//使用字符型的二维数组
    11. char *pStr[N];
    12. printf("How many countries?");
    13. scanf("%d",&n);
    14. getchar();//读走缓冲区的回车符
    15. printf("Input their name:\n");
    16. for(i=0;i
    17. {
    18. pStr[i]=name[i];//让pStr指向name的第i行
    19. gets(pStr[i]);//输入第i个字符串到pStr指向的内容
    20. }
    21. SortString(pStr,n);//这时候排序的就是pStr
    22. printf("Sorted results:\n");
    23. for(i=0;i
    24. {
    25. puts(pStr[i]);//输出排序后字符
    26. }
    27. return 0;
    28. }
    29. void SortString(char *ptr[],int n)
    30. {
    31. //指针数组作函数参数,来用交换法实现字符串的排序
    32. int i,j;
    33. char *temp=NULL;//因为交换的是字符串的地址值,所以temp需要为指针变量
    34. for(i=0;i-1;i++)
    35. {
    36. for(j=i+1;j
    37. {
    38. if(strcmp(ptr[j],ptr[i])<0)//用strcmp()函数实现字符串的比较功能
    39. {
    40. temp=ptr[i];//这里就使用赋值运算符即可
    41. ptr[i]=ptr[j];
    42. ptr[j]=temp;
    43. }
    44. }
    45. }
    46. }

    11.5

    演示命令行的参数与函数main()各形参之间的关系。

    1. //例11.5 演示命令行的参数与函数main()各形参之间的关系。
    2. #include
    3. int main(int argc,char *argv)//带参数的main()函数定义,argc和argv是惯例
    4. {
    5. int i;
    6. printf("The number of command line arguments is:%d\n",argc);
    7. printf("The program name is:%s\n",argv[0]);
    8. if(argc>1)
    9. {
    10. printf("The other arguments are following:\n");
    11. for(i=1;i
    12. {
    13. printf("%s\n",argv[i]);
    14. }
    15. }
    16. return 0;
    17. }

    11.6

    编程输入某班学生的某门课成绩,计算并输出其平均分。学生人数由键盘输入。

    1. //例11.6 编程输入某班学生的某门课成绩,计算并输出其平均分。学生人数由键盘输入。
    2. #include
    3. #include
    4. void InputArray(int *p,int n);
    5. double Average(int *p,int n);
    6. int main(void)
    7. {
    8. int *p=NULL,n;
    9. double aver;
    10. printf("How many students?");
    11. scanf("%d",&n);
    12. p=(int *)malloc(n*sizeof(int));//有多少学生就对应开辟多少空间
    13. if(p==NULL)//防止出现分配不成功的情况
    14. {
    15. printf("No enough memory!\n");//提醒用户空间分配失败
    16. exit(1);//结束程序
    17. }
    18. printf("Input %d score:",n);
    19. InputArray(p,n);//输入学生成绩
    20. aver=Average(p,n);//计算平均分
    21. printf("aver=%.1f\n",aver);
    22. free(p);//千万不要忘记释放空间
    23. return 0;
    24. }
    25. void InputArray(int *p,int n)
    26. {
    27. int i;
    28. for(i=0;i
    29. {
    30. scanf("%d",&p[i]);
    31. }
    32. }
    33. double Average(int *p,int n)
    34. {
    35. int i,sum=0;
    36. for(i=0;i
    37. {
    38. sum+=p[i];
    39. }
    40. return (double)sum/n;//注意强制转换
    41. }

    11.7

    编程输入m个班学生(每班n个学生)的某门课成绩,计算并输出平均分。班级数和每班学生数由键盘输入。

    1. //例11.7 编程输入m个班学生(每班n个学生)的某门课成绩,计算并输出平均分。班级数和每班学生数由键盘输入。
    2. #include
    3. #include
    4. void InputArray(int *p,int m,int n);
    5. double Average(int *p,int m,int n);
    6. int main(void)
    7. {
    8. int *p=NULL,m,n;
    9. double aver;
    10. printf("How many classes?");
    11. scanf("%d",&m);
    12. printf("How many stuents in a class?");
    13. scanf("%d",&n);
    14. p=(int *)calloc(m*n,sizeof(int));//申请内存
    15. if(p==NULL)//防止出现分配不成功的情况
    16. {
    17. printf("No enough memory!\n");//提醒用户空间分配失败
    18. exit(1);//结束程序
    19. }
    20. printf("Input %d score:",n);
    21. InputArray(p,m,n);//输入学生成绩
    22. aver=Average(p,m,n);//计算平均分
    23. printf("aver=%.1f\n",aver);
    24. free(p);//千万不要忘记释放空间
    25. return 0;
    26. }
    27. void InputArray(int *p,int m,int n)
    28. {
    29. int i,j;
    30. for(i=0;i
    31. {
    32. printf("Please enter scores of class %d:\n",i+1);
    33. for(j=0;j
    34. {
    35. scanf("%d",&p[n*i+j]);
    36. }
    37. }
    38. }
    39. double Average(int *p,int m,int n)
    40. {
    41. int i,j,sum=0;
    42. for(i=0;i
    43. {
    44. for(j=0;j
    45. {
    46. sum=sum+p[n*i+j];
    47. }
    48. }
    49. return (double)sum/n;//注意强制转换
    50. }

  • 相关阅读:
    创建一个用户test且使用testtab表空间及testtemp临时表空间并授予其权限,密码随意
    智慧的仓库管家——WMS
    C++11
    投资黄金:如何选择正确的黄金品种增加收益?
    算法|每日一题|倍数求和|容斥原理
    python面试题总结(一)
    Css之使用calc()计算宽高(vw/vh)
    (Spark Connect)使用Aerospike的 Spark 连接器
    R语言使用rpart包拟合随机森林回归模型:使用predict函数和训练好的模型进行预测推理、使用plot函数可视化线图对比预测值和实际值曲线
    postman连接websocket, 建立连接、聊天测试(v8.5.1)
  • 原文地址:https://blog.csdn.net/gy200203/article/details/140364387