第四次课大纲

时间:2020-12-28 14:27:39

  强调作业!

  (1)数组名等于数组第0个元素的地址,但含义不同。

  使用int a[5];定义数组a,编译器进行编译时分配了5个连续的空间,同时将数组名a解析为数组第0个元素的地址,即a=&a[0],虽然数组名a和&a[0]值相同,但是含义是不一样的,使用sizeof分别输出长度就会发现,a代表的是整个数组,而&a[0]只是表示自己。

第四次课大纲第四次课大纲
 1 #include <stdio.h>
2
3 int main(){
4 int a[5];
5 printf(" a=%p\n",a);
6 printf("&a=%p\n",&a[0]);
7
8 printf("sizeofa=%lu\n",sizeof(a));
9 printf("sizeof&a[0]=%lu\n",sizeof(&a[0]));
10
11 return 0;
12 }
View Code

  (2)当数组名被当作值使用时,数组名相当于一个常量指针

   在作为函数参数时和表达式时,数组名a被编译为指针,可以使用指针的*运算符。当指针指向数组名时,指针也可以使用数组的[]运算。所以下列四种函数的原型是等价的:

1 int sum(int *a);
2 int sum(int *p);
3 int sum(int a[]);
4 int sum(int p[]);

  数组名与普通指针不同的是,数组名不可以被赋值,相当于一个常量指针,它是这个数组就不可以是别的数组了,所以数组在表达式中或者作为函数参数时相当于常量指针,不可以赋值,不可以代表别的东西。

  (3)指向数组的指针的运算

  (3.1)*(p+n)=a[n];类似形式有:+=,-=,++,--,其中加一个整数就是往前挪一些,减一个整数就是往后挪一些。

  (3.2)两个指针相减,差值不是地址相减,而是这两个地址的差除以sizeof类型。另外两个指针相加,相乘和相除都没有意义。

  (3.3)*p++等价于*p,p++等价于*(p++);*(++p)相当于p=p+1,*p;++(*p)。

  (3.4)指针的比较运算

  指针比较运算包括<,<=,==,>,>=,!=等等。指针的比较其实就是地址大小的比较,如果一个指针指向a[0],一个指针指向a[5],很明显a[0]要比a[5]的值要小,数组是顺序递增排列的。

  (4)根据上述方法引用数组各元素值的方法(课本P233给出了3种方法)

  最普通的如下,可以修改a[10]改为*(a+i),a修改为指针p,或者不使用变量i只使用p,也可将for改为while。需要注意两点:i):a++不可以;ii)若使用指针p,必须注意p指向哪个元素,p可以不指向数组的第一个元素。

  (5)指针与二维数组

   定义一个3行4列的二维数组int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}},a是数组名,二维数组a可以看作3个一维数组。在二维数组的第一行中的四个元素是:a[0][0]、a[0][1]、a[0][2]、a[0][3],假设将这一行当成一维数组b的话,那么该行的四个元素是b[0]、b[1]、b[2]、b[3],b是首元素的地址,b+1=&b[1],b+2=&b[2],b+3=&b[3],将这里的b都替换为二维数组的a[0],那么a[0]是第一行的首地址,a[0]+1=&a[0][1],a[0]+2=&a[0][2],a[0]+3=&a[0][3]。类似的,a[1]是第二行的首地址,a[2]是第三行的首地址。

  另外a是数组的首地址,也就是首元素的首地址,在二维数组里,首元素不是一个简单的整型元素,而是第一行一维数组,所以a=a[0],值是相同的,但是含义不同,可取a和a[0]的sizeof()查看长度,并且虽然a=a[0],但是a+1!=a[0]+1,a+1指向二维数组的第二行,而a[0]+1则指向第0行第1列的元素即a[0][1]。那么想要使a[0]+1使用a表达,则应该是*(a)+1或者*(a+0)+1。而&a[1][2]=*(a+1)+2。

第四次课大纲

  (6)动态内存分配

  在定义数组时,编译器根据中括号里的数组或者初始值来分配数组的长度,数组长度都是固定不变的,那么数组的长度能否动态定义,在C99标准中可以使用下述方法完成:

第四次课大纲View Code

  在C99之前是不可以这么定义的,而是使用malloc函数来动态分配内存,比如 int *a=(int *)malloc(n*sizeof(int)),申请n*sizeof(int)个内存,比如想要申请120个字节,那么就是需要30个int,即malloc(30*sizeof(int)),那么申请这么多空间后将返回值转换为int *类型,具体可以这么写:

第四次课大纲View Code

  malloc函数是在stdlib.h头文件中定义的,所以在使用malloc函数时要添加头文件,函数原型为void * malloca(size_t,size),size_t在这里不做介绍,往后会详细介绍。malloca的含义是申请空间,大小是以字节为单位的,大小由size确定,如果你要很多个int类型的空间,那么大小是size*sizeof(int),返回的结果是void *,void*表示有一个指针指向一个内存,但是不知道指向的内存的类型是什么?那么如果你需要int类型的内存空间,那么就需要将返回值类型强制转换为(int*)。malloc申请空间后,使用该空间后还必须做的事情就是释放空间,怎么释放,就是使用free()来释放。

  在C99标准下,上述两种方法一样吗?还是不一样的,使用变量定义数组大小无法手动释放空间,在一个函数运行期间,系统为该函数中数组所分配的空间会一致存在,指导该函数运行完毕,数组空间才会被释放。另外变量定义数组大小的方法,不能跨函数使用。而动态内存分配malloc就能很好的解决这些问题。更详细的区分需要同学自己去探索了,这里不详述。

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

  指针与二维数组没有来得及讲。其他内容都讲解了。