C语言中数组和指针是两个常用的变量
数组:
C语言中定义一个数组a时,如:int a[5];编译器根据指定的元素个数和元素的类型分配确定大小(元素类型大小元素个数)的一块内存,并把这块内存的名字命名为a。名字a一旦与这块内存匹配就不能被改变。
a[0],a[1]等是a的元素,但并非元素的名字。数组的每一个元素都是没有名字的。不能把数组当一个整体来进行读写操作。数组可以以指针的形式访问(a+i);也可以以下标的形式访问,如:a[i]。但其本质都是a所代表的数组首元素的首地址加上 i*sizeof(类型)个 byte 作为 数据的真正地址。
比如:
/*这种做法是错误的,s作为右值时其意义与&s[0]是一样,代表的是数组首元素的首地址,
但s不能作为左值,我们只能访问数组的某个元素而无法把数组当一个总体进行访问。
所以a[i]当成左值是没问题的*/
char s[8];
s = "Good!";
//下面这种方法是对的,声明了字符指针和一个匿名的字符串,s里面存的是一块内存的首地址
char *s;
s="good!";
//还有种写法也是正确的
char s[8] = "Good!";
指针:
在 32 位系统下,不管什么样的指针类型,其大小都为 4byte。可以测试一下 sizeof(void *)
指针和数组:
#include "stdio.h"
int main(int argc, char const *argv[])
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1); //a表示的是数组的首地址
printf("%d,%d\n",*(a+1),*(ptr-1));
return 0;
}
上面代码的结果是2,5,对指针进行加 1 操作,得到的是下一个元素的地址,而不是原有地址值直接加1。
所以,一个类型为 T 的指针的移动,以 sizeof(T) 为移动单位。
因此,对上题来说,a 是一个一维数组,数组中有 5 个元素; ptr 是一个 int 型的指针。
&a + 1: 取数组 a 的首地址,该地址的值加上 sizeof(a) 的值,即 &a + 5*sizeof(int),也 就是下一个数组的首地址,显然当前指针已经越过了数组的界限。
(int *)(&a+1): 则是把上一步计算出来的地址,强制转换为 int * 类型,赋值给 ptr。
注意
a、&a的区别:
a,&a的值是一样的,但意思不一样,a是数组首元素的首地址,也就是a[0]的首地址,&a是数组的首地址。
同理:a+1 是数组下一元素的首地址,即 a[1]的首地址,&a+1 是下一 个数组的首地址
指针数组和数组指针:
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身
决定。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32位系统下永远是占4个字节, 至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。
下面到底哪个是数组指针,哪个是指针数组呢:
A),int * p1[10];
B),int (p2)[10];
“[]”的优先级比“”要高。p1 先与“[]”结合,构成一个数组的定义,int* 修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含10个指向int 类型数据的指针,即指针数组。
在这里“()”的优先级比“[]”高,“*”号和p2构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚p2是一个指针,它指向一个包含10个int类型数据的数组,即数组指针。
#include "stdio.h"
int main(int argc, char const *argv[])
{
char a[5]={'A','B','C','D'};
char (*p)[5];
p = &a;
printf("%c,%c\n",*a,*(*p+1));//**p+1是错的
return 0;
}
网友评论