本文共 3140 字,大约阅读时间需要 10 分钟。
- 数组名不可以改变,而指向数组的指针是可以改变的。
- 指针指向字符串,此时的字符串是不能改变的;而字符数组定义的字符串,字符是可以改变的。
- 求数组长度时,借用数组名可求得数组长度,而借用指针却得不到数组长度。
遍历方式一:
#includeint main(void){ int a[5] = { 0, 1, 2, 3, 4 }, * p = a; char i; // 数组遍历方式一 for (i = 0; i < 5; i++) { printf("a[%d] = %d\n", i, *p++); } return 0;}
a[0] = 0a[1] = 1a[2] = 2a[3] = 3a[4] = 4
数组遍历方式一:使用指针遍历数组元素,*p++等价于*(p++),即指针指向的地址每次后移一个单位,然后再取地址上的值。这里的一个单位是sizeof(int)个字节。
遍历方式二:(错误)
#includeint main(void){ int a[5] = { 0, 1, 2, 3, 4 }, * p = a; char i; // 数组遍历方式二 for (i = 0; i < 5; i++) { printf("a[%d] = %d\n", i, *a++); } return 0;}
- error: value required as increment operand
- 因为数组名的指向是不可以改变的,使用自增运算符自增就会改变其指向,这是不对的,数组名只能指向数组的开头。
遍历方式二:(正确)
#includeint main(void){ int a[5] = { 0, 1, 2, 3, 4 }, * p = a; char i; // 数组遍历方式二 for (i = 0; i < 5; i++) { printf("a[%d] = %d\n", i, *(a+i)); } return 0;}
- *(a+i)相当于是指针通过偏移量,找到具体的值,而不是改变指针本身
- *(a+i)与a[i]是等价的
//字符串定义方式一char str[] = "happy";//字符串定义方式二char *str = "happy";
- 方式一:字符串中的字符是可以改变的。如可以使用类似str[3]=’q’这样的语句来改变其中的字符。原因就是:这种方式定义的字符串保存在全局数据区或栈区,是可读写的。
- 方式二:字符串中的字符是不可以改变的。原因就是:这种方式定义的字符串保存在常量区,是不可修改的。
#includeint main(void){ int a[] = { 0, 1, 2, 3, 4 }, * p = a; char len = 0; // 求数组长度方式一 printf("方式一:len=%d\n", sizeof(a) / sizeof(int)); // 求数组长度方式二 printf("方式二:len=%d\n", sizeof(p) / sizeof(int)); return 0;}
方式一:len=5方式二:len=1
- 方式一:借用数组名来求数组长度,可求得数组有5个元素,正确。
- 方式二:借用指针求数组长度,求得长度为1,
错误。原因是:
- p只是一个指向int类型的指针,编译器不知道其指向的是一个整数还是指向一个数组。
- sizeof(p)求得的是p这个指针变量本身所占用的字节数,而不是整个数组占用的字节数。
- 对于数组 a,它的类型是 int [6],表示这是一个拥有 6 个 int 数据的集合,1 个 int 的长度为 4,6 个 int 的长度为 4×6 = 24,sizeof 很容易求得。
- 对于指针变量 p,它的类型是 int *,在 32 位环境下长度为 4,在 64 位环境下长度为 8。
- 归根结底,a 和 p 这两个符号的类型不同,指代的数据也不同,它们不是一码事,sizeof 是根据符号类型来求长度的,a 和 p 的类型不同,求得的长度自然也不一样。
编译器在编译过程中会创建一张专门的表格, 用来保存名字以及名字对应的数据类型、地址、作用域等信息。sizeof 是一个操作符,不是函数,使用 sizeof 时可以从这张表格中查询到对应符号的长度。
以上内容,来源博文:
1 | 2 | 3 |
---|---|---|
a[i] = p[i] | *(p+i) = *(a+i) | *p + 1 = *a + 1 |
#includeint main(void){ int a[] = { 1, 2, 3, 4, 5 }, * p, i = 2; p = a; printf("p[i]---------%d \n", p[i]); printf("a[i]---------%d \n", a[i]); printf("\n"); printf("*(p + i)---------%d \n", *(p+i)); printf("*(a + i)---------%d \n", *(a+i)); printf("\n"); printf("*p + i---------%d \n", *p + i); printf("*a + i---------%d \n", *a + i);}
p[i]---------3a[i]---------3*(p + i)---------3*(a + i)---------3*p + i---------3*a + i---------3
- 取下标操作符 [ ]是建立在指针的基础上,它的作用是使一个指针和一个整数相加,产生出一个新的指针,然后从这个新指针(新地址)上取得数据;
- 取下标操作符的两个操作数是可以交换的,它并不在意操作数的先后顺序。如果希望访问第 3 个元素,那么可以写作 a[3],也可以写作 3[a]
- a[3] 等价于 *(a + 3),3[a] 等价于 *(3 + a),仅仅是把加法的两个操作数调换了位置。
- 使用下标时,编译器会自动把下标的步长调整到数组元素的大小。数组 a 中每个元素都是 int 类型,长度为 4 个字节,那么 a[i+1]和 a[i]在内存中的距离是 4(而不是 1)。
- 把作为形参的数组和指针等同起来是出于效率方面的考虑。
- 数组是若干类型相同的数据的集合,数据的数目没有限制,可能只有几个,也可能成千上万。如果要传递整个数组,无论在时间还是内存空间上的开销都可能非常大。而且绝大部分情况下,我们其实并不需要整个数组的拷贝,我们只想告诉函数在那一时刻对哪个特定的数组感兴趣。
#includevoid func(char arr[]) { arr[2] = 'd'; printf("arr[2]--------%c \n", arr[2]);}int main(){ char arr[] = "abcd"; func(arr); // 此时,将数组名传递给函数,就是代表了数组的指针}
arr[2]--------d
以上博文,来源:
转载地址:http://hxeab.baihongyu.com/