理解数组与指针

int a[10];

a本身是数组名也是指向第一个数组元素的指针。a+1是指向第二个数组元素的指针。也就是说a这个指针的值就是&a[0]。

&a这个指针和a都指向同一个内存地址,但是&a这个指针的意义却是指向整个数组,&a+1指向a这个数组结束后的位置。

声明一个指针指向来指向这个数组可以这样声明 int *p = a 。而如果要声明能指向整个数组空间大小的指针,需要这样声明 int (* p) [10] = &a(二维数组中用这种指针来指向每个子数组,三维数组就是 int(*p)[10][10],可依次类推到多位数组);

int b[10][10];

b是二维数组,可以看成是一维数组的数组。b指针指向第一个一维数组,和b[0]指向的地址相同,也和b[0][0]的地址相同,也就是&b[0][0]。但是代表的意义不同,*b=b[0],*b[0]=b[0][0],也就是**b=b[0][0]。

&b是指向整个二维数组的指针,&b+1指向整个二维数组结束后的位置。

b是指向二维数组的第一个数组元素的指针,b+1是指向二维数组的第二个数组元素的指针。

b[0]是指向二维数组第一个数组元素的第一个元素的指针,b[0]+1是指向二维数组第一个数组元素的第二个元素的指针。

在函数形参中int (*p) [10]和int p[] [10]等价,都是指向一个长度为10的int数组的指针,注意如果用指针形式则不能省掉(),因为[]符号优先级大于*,如果去掉()写成int * p [10]则是定义一个包含10个int类型指针的数组。如 char * p [3] = {"abc","qwe","rfvrty"},这里p是一个指针数组,存储3个字符串常量的地址。可见,如果用字符串数组(就是二维字符数组)来存储这些内容的话要定义为char p[3][6] = {"abc","qwe","rfvrty"}才能装得下,明显比指针数组的方式效率低,所以如果不是要修改字符串的值得情况下应优先考虑指针数组的形式。

数组传递给函数是传递数组的指针,如果不希望在函数中对数组做修改的话,最好将形参定义为const来保证原数组不被修改,func(const int * ar)。如果是定义一个指针只指向一个数组而不能被改指他处则要这样 int * const ar = a。

定义一个字符串可以用下面三种方式:

#define STR "hello"

const char s[10] = "hello";

const char s[] = "hello"; //这样可以自动计算需要的元素个数

const char * sp = "hello";

这里如果不用const,则s[]定义的字符串可以修改内容,但是*sp这种是不可修改内容的,因为*sp是直接指向字符串常量的指针,而s[]是在内存中重新分配的空间,将字符串常量的值添加进来。这点可以通过比较定义的字符数组和字符串常量的地址来验证(我目前使用的clang编译器对出现多次的相同字符串常量是存储在同一个位置的,而且存储静态数据和动态数据的地址位数都不同。可能有其他编译器会存储在不同位置)。

另外,s[]这种形式定义的数组,s是常量,本身只能指向数组的首地址,可以用s+1来指向下一个元素地址,但是不可以改变s本身存储的地址值,如++s或s++都不行。*sp中sp是变量,定义时存储的是字符串常量的首地址,sp+1指向数组的第二个元素,但是可以对sp内存储的内容做修改,如++sp,sp++都可以。两者在使用时也都可以使用s[1]和*(s+1)这两种方法来取数组元素的值。

posted @ 2020-11-22 18:14  大牛等等我  阅读(232)  评论(0编辑  收藏  举报