===================数组和指针的基本关系: 数组大小和起始地址指针
1、C语言只有一维数组,而且其大小必须在编译期间确定下来。 但是其组元素可以是任何类型,如另外的数组。因此可以构建多维数组。
2、对一个数组,只可确定其大小,以及获得指向组下标为0的元素的指针。
其他的关于数组的操作,如组下标等,也是经由指针进行的,二者是等价的。
3、int calender[12][31];
sizeof(calender) = 12*31*4;
除了sizeof以外,其他的操作总被转换成为calender数组的起始元素的指针。
===================指针的基本操作
4、通过指针改变变量的值:
任何指针都是指向某类型的变量,可以给其赋变量地址,并经由指针改变变量的值。
int *p;
int i;
p = &i;
*p = 12;
5、指针的偏移:
p+1; p++; ++p;
p-1; p--; --p;
表示 指向p指向的组元素的前后元素。
在内存中的地址偏移是 : (p的指向类型)*1
6、指针的加减
如果两个指针指向同一个组元素,则可以把两个指针相加减。 int p = q + i;
=============数组和指针
7、数组首地址和指针类型
int a[3], *p;
p = a; 是把数组a中下标为0的元素的地址赋给 p。即p = &a[0]...
区别 p = &a; &a是一个指向数组的指针,而p是指向整型变量的指针,二者类型不匹配。
8、数组元素和指针
*a = a[0]; *a 是 a[0]的引用,属同一个元素。
*(a+1) = a[1];
*(a+i) = a[ i ];
9、二维数组的指针和行地址
int a[12][31];
int *p;
p = a[4]; //第五行首地址; 不是 p=&a[4]; a[4]是 int (*)[31]类型,& 则是变成int(*)类型。
p指向a[4]中下标为0的元素的地址: &a[4][0]... a[4]为a 第五个元素。
a[4]是a的第五个元素,是12个有31个整数元素的数组之一。 a[4]也表现为一个有31个整型元素的组行为。
a[4][7] = *( a[4] + 7) = *( *(a + 4) + 7);
-------------
& 是取地址运算符。而* 是指针运算符或叫间接访问运算符。
(1)a[0]+1=&a[0][1]=*(a+0)+1;
同理:a[0][1]=*(a[0]+1)=*(*(a+0)+1)=*(a+1);
(2)a[i]的性质:a如果是一维数组名,这a[i]为组元素有物理内存。如果a是二维数组,则a[i]代表一维数组名,只是一个地址并不占有内存单元。
(3)二维数组名是指向行的,如a+1;1表示一行中全部元素所占字节数。而a[0]=*a是指向列的,如a[0]+1。
@ 行指针前加上*,就转换成了列指针。而列指针前加上了&,就转换成了行指针了。
@ 同样&a[i]在这里并不是a[i]的物理地址,没有a[i]这个变量,这只是一种地址的计算方法。
@ a+i和&a[i]是指向行的,而a[i]和*a,*(a+i)是指向列的。
----------------------
10、指向数组的指针
声明指向数组的指针: 参考函数的指针 int (*p)();
int (*p) [31];
int a[12][31];
p = a;
则 *p是一个有31个整型元素的数组。 p指向数组的第一个元素 a[0]。
char arrayT[2][5]={0};
char *s[3] = {"aaaaa", "bbb", "ccccc"};
char (*p)[5] = &arrayT[0];
p = arrayT+1;
char arrayB[] = "bbbc";
p = &arrayB;
11、数组行指针和列指针的转换:
数组行指针 加上* 成为列指针; 数组列指针加上 &成为行指针。
12、含多个指针的数组:
char *argv[ ]表示指针数组;区别char (* argv)[ ]数组指针。
@清空 一整年的日历:
int calender[12][31];
int month;
for( month=0; month<12; month++)
{
int day;
for(day = 0; day<31; day++)
{
calender[month][day] = 0;
}
}
int (*monthp)[12];
for(monthp = calender; monthp<&calender[12] monthp++)
{
int *dayp; //每个月的操作
for(dayp= *monthp; dayp<&(* monthp)[31]; dayp++ )
{
*dayp = 0;
}
}
///
1、如何在C中为一个数组分配空间。
如果是栈的形式,Type s[N]定义后系统自动分配空间,分配的空间大小受操作系统限制;
若是堆的形式,Type *s; s = (Type *)malloc(sizeof(Type) * N);分配的空间大小不受操作系统限制。
///例题分析
1、数组名作为首地址
指出下面代码的输出,并解释为什么。
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);//指针是数组类型,+1相当于加20.如果是(a+1)是+4
printf("%d %d\n", a, ptr);
printf("%d, %d", *(a+1),*(ptr-1));
}
输出:1245036 1245056 2,5
*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int).
int *ptr=(int *)(&a+1);
则ptr实际是&(a[5]),也就是a+5
原因如下:
&a是数组指针,其类型为 int (*)[5];
而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同
a是长度为5的int数组指针,所以要加 5*sizeof(int),所以ptr实际是a[5].
但是prt与(&a+1)类型是不一样的(这点很重要),所以prt-1只会减去sizeof(int*).
a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].
2、数组名作为首地址
题目如下,找出其中的不妥之处。
{
char *p1, *p2;
char ch[12];
char **pp;
p1 = ch; //指向数组首地址 &ch[0]
pp = &ch; //错误用法
p2 = *pp;
}
问p1和p2是否相同
首先,数组ch是没有初始化的。其次,一个比较隐含的地方是,数组名可以代表数组第一个元素的首地址,这个没有问题,但是,数组名并非一个变量,数组分配完成后,数组名就是固定的,地址也是固定的。这样导致的结果就是绝对不能把数组名当作变量来进行处理。上述题目中,pp=&ch,显然是把数组名当作指针变量来使用了,这样肯定出问题。