程序设计复习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <stdio.h> #include <string.h> int main(){ int a,b; void exchange(int *p,int *q); scanf("%d %d",&a,&b); int *m,*n; m=&a; n=&b; exchange(m,n); printf("a是%d,b是%d",a,b); }
void exchange(int *p,int *q){ int *p0; *p0=*p; *p=*q; *q=*p0; }
|
这段代码看似没问题,实际上有一个严重的错误。函数中定义的p0
开始是并没有明确的指向,是一个野指针,但第二行直接进行了解引用操作,会导致编译直接报错。
正确的写法应该是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <stdio.h> #include <string.h> int main(){ int a,b; void exchange(int *p,int *q); scanf("%d %d",&a,&b); int *m,*n; m=&a; n=&b; exchange(m,n); printf("a是%d,b是%d",a,b); }
void exchange(int *p,int *q){ int *p0; p0=*p; *p=*q; *q=p0; }
|
对于一个一维数组a[5]
,由于用来存放数组的区域是一块在栈中静态分配的内存,且是连续的,而数组名是这块内存的代表,它被定义为这块内存的首地址,故
- 它的数组名
a
是数组首元素的地址。它是一个符号地址常量,不能用作指针。即a==&a[0]
1 2 3 4 5 6 7 8 9
| #include <stdio.h>
int main(){ int a[12]={1,2,3,4,5,6,7,8,9,10,11,12}; int p; p=(a==&a[0]); printf("%d\n",p); return 0; }
|
结果:
- 由于存储数组的内存空间是连续的,因此
a+i
是a[i]
的地址。
- 由上一条,
*(a+i)==a[i]
和a+i==&a[i]
的结果都应该是True
。因此可以通过指针访问数组元素
一个二维数组的本质是又若干个一维数组作为元素构成的数组。考虑一个二维数组a[2][3]
。这个数组有2个元素,每个元素是一个含有3个元素的一维数组。
若int a[2][3]={{1,3,2},{4,5,6}}
a[0]
是这个二维数组当中的第一个元素,即{1,3,2}
考虑a[1][2]
时,由上条,把a[1]
看做一个整体,它表示的是a
中第二个元素这个数列,即{4,5,6}
。那么a[1][2]
就是a[1]
的第三个元素,是6
。
a
是一个地址常量,它的值是a
中第一个元素所在的内存地址,即a[0]
的内存地址。又因为a[0]
作为一个数组,它的内存地址就是a[0][0]
的地址。
a[0]
是a
中第一个元素这个数列的数组名,它是a[0]
的首元素的地址常量。因此在数值上,a
与a[0]
相同。
1 2 3 4 5 6 7 8 9
| #include <stdio.h>
int main(){ int a[2][3]={{1,3,2},{4,5,6}}; int p; p=(a==a[0]); printf("%d\n",p); return 0; }
|
这里会输出1
,但会发生警告:
1 2 3 4
| new.c:6:9: warning: comparison of distinct pointer types ('int (*)[3]' and 'int *') [-Wcompare-distinct-pointer-types] p=(a==a[0]); ~^ ~~~~ 1 warning generated.
|
这是因为在C中,此处的a
类型是int (*)[3]
,即指向含有三个元素数组的指针,而a[0]
是普通的整型指针,直接比较因为类型并不完全相同会报错。但他们的值事实上的确是相同的。
*a
表示对a进行解引用,即得到a
中的首元素a[0]
。然而a[0]
作为数组名直接使用,它的本质仍然是a[0]
数组的首地址。因此
1 2 3 4 5 6 7
| #include <stdio.h>
int main(){ int a[2][3]={{1,3,2},{4,5,6}}; printf("%p,%p\n",a,*a); return 0; }
|
会得到
1
| 0x7ff7b63e62f0,0x7ff7b63e62f0
|