1.指针和数组笔试题解析
关键:数组名在两种情况下是指整个数组:
(1)sizeof(数组名)(2)&数组名
其它的情况下,都是代表数组的首元素地址。
例题 1 :一维数组
int main()
{
//一维数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
//此时的表达式只是数组名a,代表的是整个数组,sizeof计算的是整个数组的大小,为4*4=16个字节。
printf("%d\n", sizeof(a + 0));
//a+0是表达式,数组名a代表的是数组的首元素地址,为int型指针变量,
//+0后还是int型指针变量,大小是4/8个字节。
printf("%d\n", sizeof(*a));
//*a不是单纯的数组名,a表示的首元素的地址,解引用后为int整数1,其大小是4个字节。
printf("%d\n", sizeof(a + 1));
//a+1是表达式,数组名a表示的是首元素的地址,为int型指针变量,
//+1后还是int型指针变量,大小是4/8个字节。
printf("%d\n", sizeof(a[1]));
//a[1]表示的整型2,为int变量,其大小是4个字节
printf("%d\n", sizeof(&a));
//此时的数组名a表示的整个数组,&a后表示的数组指针,是指针,占4/8个字节
printf("%d\n", sizeof(*&a));
//此时的数组名a表示的是整个数组,&a后解引用后是数组名a,此时单纯的数组a,表示的整个数组
//其大小是4*4=16个字节
printf("%d\n", sizeof(&a + 1));
//&a是整个数组的地址,+1后还是表示地址,是地址,其大小是4/8
printf("%d\n", sizeof(&a[0]));
//数组首元素取地址,是地址,其大小是4/8
printf("%d\n", sizeof(&a[0] + 1));
//数组首元素取地址后+1还是表示地址,是地址,其大小是4/8。
return 0;
}
例题 2 :字符数组
int main()
{
//字符数组
char arr[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };
printf("%d\n", sizeof(arr));
//数组名表示这个数组,计算的整个数组的大小,为1*6=6
printf("%d\n", sizeof(arr + 0));
//此时为表达式,数组名表示的首元素的地址,+0之后还是地址,是地址,其大小为4/8
printf("%d\n", sizeof(*arr));
//数组名arr此时为数组首元素,解引用后为字符‘a’,其大小为1个字节
printf("%d\n", sizeof(arr[1]));
//此时计算的数组第二元素‘b’,其大小为1个字节
printf("%d\n", sizeof(&arr));
//此时数组名为整个数组,&arr 代表是数组指针,是指针,是地址,其大小为4/8
printf("%d\n", sizeof(&arr + 1));
//此时数组名为整个数组,&arr代表的是数组指针,加一后还是指针,是地址,其大小为4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));
//&a[0]是char*类型的指针,加一后还是指针,是地址,其大小为4/8个字节。
return 0;
}
#include<string.h>
int main()
{
char arr[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };
printf("%d\n", strlen(arr));
//此时的数组名是首元素的地址,但是该数组没有以'\0'结尾,所得的值是随机的
printf("%d\n", strlen(arr + 0));
//同上
printf("%d\n", strlen(*arr));
//此时的数组名是首元素的地址,解引用后是‘a’->97 ,此时非法访问地址97,error
printf("%d\n", strlen(arr[1]));
//同上
printf("%d\n", strlen(&arr));
//此时的数组名是整个数组,地址是首元素的地址,但是没有结束符结尾,所得值是随机的
printf("%d\n", strlen(&arr + 1));
//同上
printf("%d\n", strlen(&arr[0] + 1));
//同一
return 0;
}
int main()
{
char* p = “abcdef”;
printf("%d\n", sizeof(p));
//p是一个char *类型的指针,是地址,其大小为4/8个字节
printf("%d\n", sizeof(p + 1));
//同上
printf("%d\n", sizeof(*p));
//p指向的是字符串的首元素a的地址,解引用后得到字符a,其大小为1个字节。
printf("%d\n", sizeof(p[0]));
//同上
printf("%d\n", sizeof(&p));
//&p是得到变量p的地址,是二级指针,是地址,其大小为4/8
printf("%d\n", sizeof(&p + 1));
//同上
printf("%d\n", sizeof(&p[0] + 1));
//&p[0]得到的是字符a的地址,加一后还是地址,是地址,其大小为4/8
printf("%d\n", strlen(p));
//得到整个字符串的长度6
printf("%d\n", strlen(p + 1));
//得到5
printf("%d\n", strlen(*p));
//*p得到字符‘a’==97,非法访问 error
printf("%d\n", strlen(p[0]));
//同上
printf("%d\n", strlen(&p));
//&p得到的是变量p的地址,不知道结束符在哪,是随机值
printf("%d\n", strlen(&p + 1));
//同上
printf("%d\n", strlen(&p[0] + 1));
//&p[0]得到的是字符a的地址,加1后得到的是字符b的地址,得到5
return 0;
}
int main()
{
char arr[] = “abcdef”;
printf(“%d\n”, sizeof(arr));
//此时数组名arr是整个数组的地址,其大小为7*1=7
printf("%d\n", sizeof(arr + 0));
//此时数组名是首元素的地址,是char*类型的数据,其大小为4/8个字节
printf("%d\n", sizeof(*arr));
//此时数组名为首元素的地址,解引用后是a,char类型,其大小为1个字节
printf("%d\n", sizeof(arr[1]));
//arr[1]为字符b,为char类型,其大小为1个字节
printf("%d\n", sizeof(&arr));
//此时的数组名是整个数组的地址,是数组指针,是地址,其大小为4/8
printf("%d\n", sizeof(&arr + 1));
//此时的数组名是整个数组的地址,,是数组指针,加1后还是数组值,是地址,其大小为4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));
//&arr[0]是字符a的地址,是char*类型的指针,+1后还是指针,是地址,其大小为4/8个字节
printf("%d\n", strlen(arr));
//此时数组名是首元素的地址,得到6
printf("%d\n", strlen(arr + 0));
//同上
printf("%d\n", strlen(*arr));
//*arr指的是字符a,非法访问--error
printf("%d\n", strlen(arr[1]));
//同上
printf("%d\n", strlen(&arr));
//此时的数组名是整个数组的地址,是首元素的地址,可得到6
printf("%d\n", strlen(&arr + 1));
//此时数组名是整个数组的地址,+1跳过整个数组,不知道结束符在哪里,得到的值是随机的
printf("%d\n", strlen(&arr[0] + 1));
//&arr[0]+1是字符b的地址,得到5
return 0;
}
例题3 :二维数组
int main()
{
//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
//此时的数组名是整个数组,其大小为3*4*4=48
printf("%d\n", sizeof(a[0][0]));
//是整数0,是int类型,其大小为4个字节
printf("%d\n", sizeof(a[0]));
//此时a[0]首行的数组名,是整行的数组,大小为4*4=16
printf("%d\n", sizeof(a[0] + 1));
//此时a[0]是首行数组首元素的地址,+1后还是int*类型的指针,是地址,其大小为4/8
printf("%d\n", sizeof(*(a[0] + 1)));
//由上知道,解引用后是int类型的整数,其大小为4
printf("%d\n", sizeof(a + 1));
//此时数组名a是首元素的地址,首元素是int [4]类型的数组,
//加1后是第二行的数组地址,是地址其大小就是4/8
printf("%d\n", sizeof(*(a + 1)));
//由上知,a+1是第二行的地址,解引用后int [4]类型的数组,其大小为4*4=16
printf("%d\n", sizeof(&a[0] + 1));
//此时a[0]是第一行数组名,&a[0]取得是第一行数组的地址,+1后是第二行数组的地址,是地址其大小就是4/8
printf("%d\n", sizeof(*(&a[0] + 1)));
//由上知&a[0] + 1是第二行的地址,解引用后是int [4]类型的数组,其大小为4*4=16
printf("%d\n", sizeof(*a));
//*a得到首元素a[0],是第一行数组的数组名,此时是第一行数组的整个数组,其大小为4*4=16
printf("%d\n", sizeof(a[3]));
//如果数组存在第四行,a[3]就是第四行的数组名,
//数组名单独放在sizeof内部,计算的是第四行的大小4*4=16
return 0;
}
总结
数组名在两种情况下是指整个数组:
(1)sizeof(数组名)(2)&数组名
其它的情况下,都是代表数组的首元素地址。
2.指针笔试题
题目 1:
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( “%d,%d”, *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
题目 2:
//结构体的大小是20个字节
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;
}
题目 3:
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;
}
题目 4:
#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;
}
注意逗号表达式
题目 5:
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;
}
题目 6:
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;
}
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);
关键是画出图