C语言 指针和数组笔试题

sizeof(数组名) —— 数组名表示整个数组
&数组名 —— 数组名表示整个数组,取出是整个数组的地址
除此之外,所有的数组名都是数组首元素地址

指针和数组笔试题

一维数组

	int a[] = { 1,2,3,4 };

	//16
	//sizeof(a),计算整个数组占内存空间大小,此时a表示整个数组
	printf("%d\n", sizeof(a));	
	//4/8,当a参与运算,此时不再是表示整个数组,而是表示数组首元素地址
	printf("%d\n", sizeof(a + 0));
	//4,a参与运算,计算的是数组第一个元素的大小
	printf("%d\n", sizeof(*a));
	//4/8,计算数组第二个元素的地址 所占空间大小
	printf("%d\n", sizeof(a + 1));
	//4,计算数组第二个元素大小
	printf("%d\n", sizeof(a[1]));

	//4/8,取出整个数组的地址,整型地址占内存4/8字节。
	printf("%d\n", sizeof(&a));
	//16,*和&可以相互抵消,仅仅计算数组a的所占空间大小
	printf("%d\n", sizeof(*&a));
	//4/8,跳过整个数组,整型地址占32位机器内存4字节
	printf("%d\n", sizeof(&a + 1));
	//4/8,取数组第一个元素的地址,地址占4/8字节
	printf("%d\n", sizeof(&a[0]));
	//4/8,取第一个元素地址,后移一位是第二个元素地址,地址占4/8字节
	printf("%d\n", sizeof(&a[0] + 1));

字符数组

	char arr[] = { 'a','b','c','d','e','f' };
	
	//6.计算整个数组占空间大小
	printf("%d\n", sizeof(arr));
	//4/8,参与运算,数组首元素地址
	printf("%d\n", sizeof(arr + 0));
	//1,数组首元素地址解引用,计算数组首元素占空间大小
	printf("%d\n", sizeof(*arr));
	//1,计算数组第二个元素占空间大小
	printf("%d\n", sizeof(arr[1]));
	//4/8,计算整个数组的地址大小
	printf("%d\n", sizeof(&arr));
	//4/8,跳过整个数组长度后,计算空间大小
	printf("%d\n", sizeof(&arr + 1));
	//4/8,计算第二位元素所占空间大小
	printf("%d\n", sizeof(&arr[0] + 1));
	
	//随机值,从数组首元素开始向后计算长度,没找到\0,结果随机值
	printf("%d\n", strlen(arr));
	//随机值,同上,没找到结束标志\0,结果随机值
	printf("%d\n", strlen(arr + 0));
	//err,计算数组首元素长度,相当于strlen('a'),没有这个功能,报错
	printf("%d\n", strlen(*arr));
	//err,相当于计算'b'长度,没有这个功能,报错
	printf("%d\n", strlen(arr[1]));
	//随机值,从首元素地址开始向后计算长度,没有明确\0,结果随机值
	printf("%d\n", strlen(&arr));
	//随机值-6,跳过整个数组(数组占内存6字节)后计算长度,比上一句代码少6位数据,结果还是随机值
	printf("%d\n", strlen(&arr + 1));
	//随机值-1,从数组第二位元素开始计算长度,比从开头计算少一。
	printf("%d\n", strlen(&arr[0] + 1));
	char arr[] = "abcdef";
	//a b c d e f \0

	//7,有隐藏的\0结束标志,所以占用空间7位
	printf("%d\n", sizeof(arr));
	//4/8,arr参与运算表示首元素地址,地址占空间4/8位字节
	printf("%d\n", sizeof(arr + 0));
	//1,首元素地址解引用,得到数组首元素,char类型占用1字节
	printf("%d\n", sizeof(*arr));
	//1,数组第二位元素占用1字节
	printf("%d\n", sizeof(arr[1]));
	//4/8,整个数组的地址,只要是地址就占用4/8
	printf("%d\n", sizeof(&arr));
	//4/8,跳过整个数组长度后,计算地址
	printf("%d\n", sizeof(&arr + 1));
	//4/8,先指向数组首元素,再后移指向数组第二位元素,最后计算地址
	printf("%d\n", sizeof(&arr[0] + 1));

	
	//6,有结束标志\0,可以正常计算数组长度
	printf("%d\n", strlen(arr));
	//6,从首元素开始计算长度,遇到\0结束
	printf("%d\n", strlen(arr + 0));
	//err,还是把字符'a'传递进去计算,报错
	printf("%d\n", strlen(*arr));
	//err,把字符'b'传递进去计算,报错
	printf("%d\n", strlen(arr[1]));
	//6,计算整个数组长度
	printf("%d\n", strlen(&arr));
	//随机值,跳过整个数组,不知道结束标志\0位置,所以随机值
	printf("%d\n", strlen(&arr + 1));
	//5,从数组第二位元素开始计算,结果5
	printf("%d\n", strlen(&arr[0] + 1));
	char* p = "abcdef";
	//p -> [a,b,c,d,e,f,\0]
	
	//4/8,p是个地址,指向'a'
	printf("%d\n", sizeof(p));
	//4/8,指针后移一位,还是地址
	printf("%d\n", sizeof(p + 1));
	//1,地址指向'a',解引用就是计算'a'的长度
	printf("%d\n", sizeof(*p));
	//1,计算'a'的长度
	printf("%d\n", sizeof(p[0]));
	//4/8,取p的地址计算,是地址就是4/8
	printf("%d\n", sizeof(&p));
	//4/8,跳过整个p,还是地址
	printf("%d\n", sizeof(&p + 1));
	//4/8,计算'b'的地址
	printf("%d\n", sizeof(&p[0] + 1));

	//6,p指针指向a,从a开始计算长度,遇到\0结束
	printf("%d\n", strlen(p));
	//5,指针后移一位,从b开始计算长度
	printf("%d\n", strlen(p + 1));
	//err,p指针指向a,解引用得到a,函数无法计算字符a长度
	printf("%d\n", strlen(*p));
	//err,函数无法计算字符a长度
	printf("%d\n", strlen(p[0]));
	//随机值,取p指针的地址,计算长度,无法知道\0位置,随机值
	printf("%d\n", strlen(&p));
	//随机值,跳过一个p指针的地址,还是无法知道\0位置,随机值
	printf("%d\n", strlen(&p + 1));
	//5,取到a的地址,后移一位得到b,也就是从b开始计算长度。
	printf("%d\n", strlen(&p[0] + 1));

二维数组

	//二维数组
	int a[3][4] = { 0 };
	/*
	0 0 0 0
	0 0 0 0
	0 0 0 0
	*/
	//48,计算整个数组大小
	printf("%d\n", sizeof(a));
	//4,计算二维数组第一行第一个元素大小
	printf("%d\n", sizeof(a[0][0]));
	//16,计算二维数组第一行大小
	printf("%d\n", sizeof(a[0]));
	//4,计算数组第一行第二个元素的地址大小
	printf("%d\n", sizeof(a[0] + 1));
	//4,数组第一行第二个元素大小
	printf("%d\n", sizeof(*(a[0] + 1)));
	//4,数组首元素地址后移一位,再计算大小
	printf("%d\n", sizeof(a + 1));
	//16,数组首元素后移一位,再解引用得到第二行元素,最后再计算第二行元素大小
	printf("%d\n", sizeof(*(a + 1)));
	//4,数组首元素地址后移一位,再计算大小
	printf("%d\n", sizeof(&a[0] + 1));
	//16,数组首元素后移一位,再解引用得到第二行元素,最后再计算第二行元素大小
	printf("%d\n", sizeof(*(&a[0] + 1)));
	//16,数组首元素解引用,得到第一行元素,最后计算第一行元素大小
	printf("%d\n", sizeof(*a));
	//16,计算数组第四行元素大小,
	//因为sizeof只表面计算表达式结果,不会真正的访问这块空间,所以不在乎这块空间是否存在
	printf("%d\n", sizeof(a[3]));

sizeof ( ),并不会把表达式的数据结果保存下来,也不会去真正访问内存区域。

	short s = 5;
	int a = 4;
	printf("%d\n", sizeof(s = a + 5));
	printf("%d\n", s);

	int arr[3] = { 0 };
	printf("%d\n", sizeof(arr[4]));

输出结果

总结

数组名的意义:

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名,这里的数组名表示整个数组,计算的是整个数组的大小。
  3. 除此之外,所有的数组名都表示首元素的地址。

指针笔试题

笔试题 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, 5 
int main() {
	int a[5] = { 1, 2, 3, 4, 5 };
	//&a取出整个数组地址,+1跳过整个数组
	int* ptr = (int*)(&a + 1);
	//*(a+1),首元素地址后移一位,得到2
	//*(ptr - 1),ptr原本指向数组后面空间,-1就前移一位,指向数据5
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}

图解


笔试题 2

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;

//假设p 的值为0x100000。 如下表表达式的值分别为多少?
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

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}

文字+图解

仔细看,二维数组初始化内容是逗号表达式,逗号表达式末尾元素才是二维数组中的数据。

p = a[0],相当于让指针 p 指向二维数组中的第一行数据

p[0],相当于 p+0,指针 p 没有发生改变。按照 %d 形式打印,结果为 1。
在这里插入图片描述


笔试题 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;
}

文字+图解

前三行代码执行后,内存情况:

  1. 创建了5*5的二维数组a。
  2. 创建了指针数组*p,只能指向4个空间。
  3. p = a,虽然不匹配,但是也能硬套上去,p一次只能指向4个字节空间。
  4. &p[4][2] - &a[4][2]指向如图绿色方块。以%d形式打印,将输出彼此相差的 -4。

  1. &p[4][2] - &a[4][2]如果以%p形式打印,内存会把 -4 的补码以十六进制形式输出。
    二进制的4个1,等于十六进制的1个F。

笔试题 6

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;
}

文字+图解

执行完前三段代码,内存情况如图:

  1. 创建二维数组。&aa+1,取二维数组的地址,+1跳过整个二维数组,最后赋值给整型指针 ptr1。

  2. aa 是二维数组的首元素地址,相当于指向第一行数据,+1将跳到第二行数据开头。

  3. *(ptr1 - 1),ptr1指针向前移动一位,指向10,解引用得到数据10.

  4. *(ptr2 - 1),ptr2指针向前移动一位,指向5,解引用得到数据5.


笔试题 7

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

文字+图解

执行前两段代码,内存情况如图:
pa++,指针下移一位,最后解引用输出结果 at。


笔试题 8

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);
	cpp指针向下移动一位,经过两次解引用得到 POINT。

	printf("%s\n", *-- * ++cpp + 3);
	这段代码复杂点
	++cpp 指针继续下移一位,解引用得到 c+1.
	*(--(c+1)),会把 c+1 变成 c,解引用得到 *c 第一个元素 "ENTER"
	最后面的 +3,因为 *c 是 "ENTER" 的首元素地址,向后推移三位再输出,结果为:ER

	printf("%s\n", *cpp[-2] + 3);
	如果不好理解 *cpp[-2] + 3,可以转换成 **(cpp-2)+3
	cpp-2,指针向上移动两位到 c+3,
	两次解引用,得到 *c 指向的元素 "FIRST",
	因为 *c 是指向 "FIRST"的首元素,+3向后数三位,然后才计算输出结果:ST

	printf("%s\n", cpp[-1][-1] + 1);
	可以把 cpp[-1][-1] + 1 转换成 *(*(cpp-1)-1)+1,
	cpp-1,指针指向 *cp 数组的第二位 c+2,
	解引用得到 c+2,然后 c+2-1 得到 c+1,导致修改了 *cp 第二位元素指向 *c 第二位地址,
	再次解引用,得到 "NEW",最后一个+1,让 *c 指针向后移动一位,才开始计算结果:EW。

指针完结,散花~

关于c语言指针这几篇文章,搞了半个星期,终于结束了~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值