C数组和指针
数组和指针的差别
数组 | 指针 |
---|---|
保存数据 | 保存数据地址 |
直接访问数据a[i]只是简单地以a+i为地址取得数据 | 间接访问数据,首先取得指针内容,把它作为地址,然后从这个地址提取数据。如果一个直接下标[i],就把指针内容加上i作为地址,从中提取数据 |
通常用于储存固定数目且数据类型相同的元素 | 通常用于动态结构 |
隐式分配和删除 | 相关函数为malloc(),free() |
自身即为数据名 | 通常指向匿名数据 |
数组和指针都可以在它们定义中使用字符串常量进行初始化,尽管看上去一样,但是底层机制却不相同
定义指针时,编译器并部位指针所指向的对象分配控件,它只是分配指针本身的空间,除非在定义的同时赋值给指针一个字符串常量进行初始化。
在ANSI C中,初始化指针所创建的字符串常量通常被定义为只读。
什么时候数组和指针相同
规则一:表达式中的数组名就是指针
例:
int a[10], *p, i = 2;
p = a;
p[i];
规则2:C语言把数组下标作为偏移量
例:
int a[10], *p, i = 2;
p = a;
for(i = 0;i < 10;i++)
{
*(p+i) = 0; //与a[i] = 0;相同
}
出自:C专家编程P204
规则三:最为函数参数的数组名等同于指针
这个比较简单就不多解释了
指针的指针
让我们暂时忘掉那些关于指针的各种类比。指针实际上存放的是内存的地址。
&
符号的意思是取地址,也就是返回一个对象在内存中的地址。
*
符号的意思是取得一个指针所指向的对象。 也就是如果一个指针保存着一个内存地址,那么它就返回在那个地址的对象。
所以当你这么写时 *ipp = ip2
,实际上是把 ipp
存的地址所对应的对象,也就是 ip1
取到,然后把 ip2
存的值赋值给 ip1
,也就是 j
的地址。
简单点就是:
&
:取址。
*
:取值。
指向数组的指针
char (*A)[10]; //指向一个内含两个char类型的值的数组
char ch[3][10] = {"qwert","terew","ytrytr"};
A = ch; //使A指向ch的第一行
printf("%s\n", A);
printf("%s\n", A[1]);
printf("%s", *(A+2)); //使用指针表示
运行结果
qwert
terew
ytrytr
警告
如果打算在指针上执行任何指针运算,应避免这种类型的声明
char (*p)[] = ch;
指针数组
指针变量和其它变量很相似,你可以声明一个指针数组来取得一个类似二维数组的效果
// A是一个内含n个指针元素的数组,每个元素都指向char类型的指针
char *A[n];
由于[ ]
的优先级高于*
所以a
先和 [ ]
结合,他还是一个数组,数组中的元素才是char *
,前面讲到char *
是一个变量,保存的地址
用于实现多维数组的指针数组有多种名字,如向量,用于激活一个在词法上封闭过程的活动记录,作为一个静态结点后跟一个链表的代替方案
下图演示了这种结构
这种数组必须用指向为字符串而分配内存的指针进行初始化,可以在编译时用一个常量初始值,亦可以用以下代码进行初始化
for(j = 0;i <= 4;j++)
pea[j] = malloc(6);
另一种方法是一次性使用malloc()分配整个X*Y个数据的数组
malloc(row_size*column_size*sizeof(char));
char *A[]和char **A区别
在C中,数组和指针通常是可以互换的,但是有一些区别:
1.用char * A []
,你不能给A
赋值,只能赋A[x]
;
使用char ** A
,您可以将值赋给A
和A[x]
。
2.用char * A[]
,你可以初始化一个数组(例如char * A [] = {“foo”,“bar”}
)并使用sizeof(A)
来获取大小(64位机器,上面的例子给你16,因为它是两个char *
的数组;用char ** A
,sizeof(A)
总是返回一个指针的大小(在64位机器上,8)。
可以写成P[][]
类型的几种定义
int p[23][12];
int *p[23];
int **p;
int (*p)[12]
区别
1.当char []
作为函数的参数时, 表示 char *
当作为函数的参数传入时, 实际上是拷贝了数组的第一个元素的地址,
所以 void test (char a[])
等同于 void test ( char * a )
char x[10]
; 然后调用 test(x)
则等同于把 x
的第一个元素的地址赋予给参数 a
.
2.char * a
和 char a[]
相同点 : a
都是指针, 指向char
类型.
不同点 : char a[]
把内容存在stack .
char *a
则把指针存在stack,把内容存在constants.
3.char * a[10]
和 char a[10][20]
相同点 : a
都是2级指针, *a
表示一级指针, **a
表示内存中存储的内容.
不同点 : char * a[10]
, 数组由char *
类型的指针组成;
char a [10][20]
表示一位放10个元素, 二维放20个元素, 值存放地是一块连续的内存区域, 没有指针.
4.小窍门 : []
和*
的数量对应, 如 char a[][]
的指针层数是2, 相当于char **a
; char *a[]
也是如此, 两层指针. 迷糊的时候数数到底有几个*
几个[]
, 就知道什么情况下存储的是内容还是地址了? 如char a[][]
的情况里面: &a
, a
, *a
都是地址, **a
是内容.
参考资料
C专家编程
C和指针(第二版)
- 感谢你赐予我前进的力量