目录
目录
1,指针与一维数组,sizeof和strlen操作
2,二维数组,sizeof操作
3,指针类型转换及解引用
1,指针与一维数组,sizeof和strlen操作
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); //16,sizeof直接操作数组名,数组名代表整个数组,sizeof(a)是整个数
//组的大小
printf("%d\n",sizeof(a+0)); //4,a+0代表首元素的地址
printf("%d\n",sizeof(*a)); //4,*a代表首元素
printf("%d\n",sizeof(a+1)); //4,a+1代表第二个元素的地址
printf("%d\n",sizeof(a[1])); //4,a[1]代表首元素
printf("%d\n",sizeof(&a)); //4,&a代表整个数组的地址
printf("%d\n",sizeof(*&a)); //16,*&a代表整个数组
printf("%d\n",sizeof(&a+1)); //4,&a+1代表跳过整个数组的地址
printf("%d\n",sizeof(&a[0])); //4,&a[0]代表取首元素的地址
printf("%d\n",sizeof(&a[0]+1)); //4,&a[0]+1代表第二个元素的地址
上述代码中,对int类型数组进行sizeof操作;
注意:一般情况下数组名代表首元素的地址,但有两种特殊情况,1:sizeof(数组名),此时代表计算整个数组的占用空间大小,此时数组名代表整个数组,而不是数组元素的首地址;2,&数组名,此时代表取这个数组的地址。
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr)); //6,sizeof直接操作数组名,arr代表整个数组
printf("%d\n", sizeof(arr+0)); //4,arr+0代表第一个元素的地址
printf("%d\n", sizeof(*arr)); //1,*arr代表第一个元素
printf("%d\n", sizeof(arr[1])); //1,arr[1]代表第一个元素
printf("%d\n", sizeof(&arr)); //4,&arr代表整个数组的地址
printf("%d\n", sizeof(&arr+1)); //4,&arr+1代表跳过整个数组的地址
printf("%d\n", sizeof(&arr[0]+1)); //4,&arr[0]+1代表第二个元素的地址
printf("%d\n", strlen(arr)); //随机值,从arr数组的首地址往后查找,直到找到\0
printf("%d\n", strlen(arr+0)); //随机值,从arr数组的首地址往后查找,直到找到\0
printf("%d\n", strlen(*arr)); //error,*arr是字符'a',从对应的ascii码的地址处查找
printf("%d\n", strlen(arr[1])); //error,*arr是字符'b',从对应的ascii码的地址处查找
printf("%d\n", strlen(&arr)); //随机值,从arr数组的地址往后查找,直到找到\0
printf("%d\n", strlen(&arr+1)); //随机值,从跳过arr数组的地址往后查找,直到找到\0
printf("%d\n", strlen(&arr[0]+1)); //随机值,从第二个元素的地址处开始查找,直到找到\0
?上述代码中,对char[]类型数组进行sizeof和strlen操作,注意strlen的查找原理是从首地址往后查找,直到找到\0,strlen函数的参数类型是const char * str,因此strlen(&arr)会报错,因为&arr的数据类型是char(*p)[ ],但程序能够运行得到结果。
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); //7,默认此种数组写法最后还有\0
printf("%d\n", sizeof(arr+0)); //4,arr+0第一个元素的地址
printf("%d\n", sizeof(*arr)); //1,*arr代表第一个元素
printf("%d\n", sizeof(arr[1])); //1,arr[1]代表第二个元素
printf("%d\n", sizeof(&arr)); //4,&arr代表整个数组的地址
printf("%d\n", sizeof(&arr+1)); //4,&arr+1代表跳过arr数组的地址
printf("%d\n", sizeof(&arr[0]+1)); //4,&arr[0]+1代表第二个元素的地址
printf("%d\n", strlen(arr)); //6,从arr数组的地址开始查找,直到找到\0
printf("%d\n", strlen(arr+0)); //6,从arr数组的首元素地址开始查找,直到找到\0
printf("%d\n", strlen(*arr)); //error,*arr代表字符'a',从对应的ascii码的地址处查找
printf("%d\n", strlen(arr[1])); //error,*arr代表字符'b',从对应的ascii码的地址处查找
printf("%d\n", strlen(&arr)); //6,从arr数组的地址开始查找,直到找到\0
printf("%d\n", strlen(&arr+1)); //随机值,从跳过arr数组的地址处开始查找,直到找到\0
printf("%d\n", strlen(&arr[0]+1)); //5,从arr数组的第二个元素地址开始查找,直到找到\0
?注意char arr[] = "abcdef"与char arr[] = {'a','b','c','d','e','f'};两种字符数组表示方法的区别,第一种默认字符中存在\0。
char *p = "abcdef";
printf("%d\n", sizeof(p)); //4,p是指针,存放的数组首元素的地址
printf("%d\n", sizeof(p+1)); //4,p+1存放的数组第二个元素的地址
printf("%d\n", sizeof(*p)); //1,*p代表数组首元素
printf("%d\n", sizeof(p[0])); //1,p[0]代表数组首元素,与*p效果一样
printf("%d\n", sizeof(&p)); //4,&p是存放指针p的地址
printf("%d\n", sizeof(&p+1)); //4,&p+1是地址,跳过p的地址
printf("%d\n", sizeof(&p[0]+1)); //4,&p[0]+1代表第二个元素的地址
printf("%d\n", strlen(p)); //6,P是数组首元素的地址,从此地址处往后查找,直到找到\0
printf("%d\n", strlen(p+1)); //5,P是数组第二个元素的地址,从此地址处往后查找,直到找到\0
printf("%d\n", strlen(*p)); //error,*p代表'a',从对应的ascii码的地址处查找
printf("%d\n", strlen(p[0])); //error,*p代表'a',从对应的ascii码的地址处查找
printf("%d\n", strlen(&p)); //随机值
printf("%d\n", strlen(&p+1)); //随机值
printf("%d\n", strlen(&p[0]+1));//5,&p[0]+1代表数组第二个元素的地址
注意对于指向数组的指针p,*(p+i)与p[i]效果一样。
2,二维数组,sizeof操作
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a)); //48,a代表整个数组
printf("%d\n",sizeof(a[0][0])); //4,a[0][0]代表第一行第一个元素
printf("%d\n",sizeof(a[0])); //16,a[0]是数组名,sizeof直接作用于数组名时,代表整个数
//组,即第一行的元素
printf("%d\n",sizeof(a[0]+1)); //4,a[0]+1代表第一行第二个元素的地址
printf("%d\n",sizeof(*(a[0]+1)));//4,*(a[0]+1)代表第一行第二个元素
printf("%d\n",sizeof(a+1)); //4,代表数组第二行的地址
printf("%d\n",sizeof(*(a+1))); //16,数组第二行所占空间大小
printf("%d\n",sizeof(&a[0]+1)); //4,代表数组第二行的地址
printf("%d\n",sizeof(*(&a[0]+1))); //16,数组第二行所占空间大小
printf("%d\n",sizeof(*a)); //16,数组第一行所占空间大小
printf("%d\n",sizeof(a[3])); //16,虽然数组实际中不存在第三行,但sizeof中不会进行真正
//的计算,只会根据数组的类型判断,也就是会判断a[3]是数组
//名,sizeof(数组名)代表整个数组的大小
对于二维数组,数组的首地址是第一行。?
3,指针类型转换及解引用
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
?&a+1表示跳过整个数组的地址,(int *)(&a + 1)表示对对这个地址强制转换为int* ptr,*(ptr - 1)表示指针减1后解引用。
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
?不同类型的指针加减操作的结果。
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}
?ptr1[-1]等价于*(ptr1-1),(int)a + 1将数组a的首元素地址转换为int后加1,相当于指向的地址移动了一个字节,x%代表以16进制形式输出。
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
?int a[3][2] = { (0, 1), (2, 3), (4, 5) };数组的中括号表达式的值最后一个数值,因此此数组是
?int a[3][2] = { 1, 3?,5},空的位置补0,a[0]代表首行数组的数组名,数组名代表首元素地址,因此指针p指向第一行的第一个元素,因此p[0]的值为1。
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
指针变量p的类型为int(*)[4],数组int a[5][5]的数组名a是数组首元素的地址,二维数组首元素是第一行,因此a的数据类型为int(*)[5],当将a赋给p时,因为数据类型不匹配,会有警告。&p[4][2] 和?&a[4][2]所指向的地址如下图所示,可看到他们相差四个字节,第一次使用p%打印时打印的是-4在内存中存储的补码,第二次打印时打印的是-4。注意&p[4][2]中,p[4]等价于*(p+4),得到的是一个一维数组,然后取这个一维数组中的第三个元素的地址,&p[4][2]等价于&(*(*(p+4)+2))。
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
?&aa是取整个数组的地址,&aa+1是跳过整个数组的地址,int*将其强制转换类型;
aa是数组名,代表首元素的地址,二维数组的首元素是首行,所以aa代表的是首行的地址,aa+1跳过首行的地址,*(aa+1)得到的是第二行的数组名,数组名是首元素的地址。
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
?一个字符类型指针指向字符串的表达形式为,char* p = "work";
因此 char *a[] = {"work","at","alibaba"};代表将三个字符串的首元素地址放到数组指针a中,然后又将数组a的首元素地址放到pa中,pa++指向a中第二个元素的地址,*pa获取数组a中存放的第二个元素,它存储的是字符"at"的首元素地址,s%打印得到at。
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}
|