c语言总结 3:指针和数组笔试题详解

数组笔试题

  • 一维数组
    例如:
    int a[] = { 1, 2, 3, 4 };
	printf("%d\n", sizeof(a));//整个数组的大小 16
	printf("%d\n", sizeof(a+0));//首元素的地址 4
	printf("%d\n", sizeof(*a));//首元素 4(a为首元素地址,*a为首元素)
	printf("%d\n", sizeof(a+1));//4第二个元素的地址
	printf("%d\n", sizeof(a[1]));//4 第二个元素
	printf("%d\n", sizeof(&a));// 4 整个数组的地址
	printf("%d\n", sizeof(*&a));//16 整个数组的大小
	printf("%d\n", sizeof(&a+1));//4 跳出整个数组指向4的后面
	printf("%d\n", sizeof(&a[0]));//4 首元素地址
	printf("%d\n", sizeof(&a[0]+1));//4 第二个元素地址
  • 字符数组
    例如:
    char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };//末尾没有'\0'
	printf("%d\n", sizeof(arr));//6 整个数组
	printf("%d\n", sizeof(arr+0));//4 首元素地址
	printf("%d\n", sizeof(*arr));//1 首元素(通过arr访问首元素地址,解引用)
	printf("%d\n", sizeof(arr[1]));//1 首元素
	printf("%d\n", sizeof(&arr));//4 整个数组地址
	printf("%d\n", sizeof(&arr+1));//4 跳过一个数组到最后一个元素的后面 
	printf("%d\n", sizeof(&arr[0]+1));// 4 第二个元素地址

    printf("%d\n", strlen(arr));//随机数 strlen找'\0'
	printf("%d\n", strlen(arr+0));//随机数 
	printf("%d\n", strlen(*arr));//error 给strlen传的参数实际为地址,arr为首元素’a',地址为97的地址,解引用发生错误
	printf("%d\n", strlen(arr[1]));//error 98的地址
	printf("%d\n", strlen(&arr));//随机值(数组的地址)x=&arr
	printf("%d\n", strlen(&arr+1));//x-6 随机值  
	printf("%d\n", strlen(&arr[0]+1));//x-1 随机值
    char arr[] = "abcdef";//末尾有'\0'
	printf("%d\n", sizeof(arr));//7
	printf("%d\n", sizeof(arr+0));//4 首元素地址
	printf("%d\n", sizeof(*arr));//1 首元素大小
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//4 整个数组的地址
	printf("%d\n", sizeof(*&arr));//7
	printf("%d\n", sizeof(&arr+1));//4 跳过一个数组到0的后面
	printf("%d\n", sizeof(&arr[0]+1));//4 第二个元素的地址
	
	printf("%d\n", strlen(arr));//6 首元素的地址,从首元素算起
	printf("%d\n", strlen(arr+0));//6
	printf("%d\n", strlen(*arr));//error 首元素的ascii码值为97,97的地址不能解引用
	printf("%d\n", strlen(arr[1]));//error 第二个元素ascii码值为98
	printf("%d\n", strlen(&arr));//6
	printf("%d\n", strlen(&arr+1));//随机值
	printf("%d\n", strlen(&arr[0]+1));//5 第二个元素的地址
    char* p = "abcdef";//末尾有'\0'
	printf("%d\n", sizeof(p));//4 指针变量大小
	printf("%d\n", sizeof(p + 1));//4
	printf("%d\n", sizeof(*p));//1  p存'a'的地址,对p解引用,为'a'的大小
	printf("%d\n", sizeof(p[0]));//1
	printf("%d\n", sizeof(&p));//4
	printf("%d\n", sizeof(&p + 1));//4char* p=&a,char* *q=&p; q+1跳过一个char*  ,&p+1 跳过一个char*
	printf("%d\n", sizeof(&p[0] + 1));//4 'b'的地址

	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	printf("%d\n", strlen(*p));//error 首元素的地址解引用为首元素
	printf("%d\n", strlen(p[0]));//error
	printf("%d\n", strlen(&p));//随机值 整个数组的地址
	printf("%d\n", strlen(&p + 1));//随机值 跳过一个char*
	printf("%d\n", strlen(&p[0] + 1));//5
  • 二维数组
    例如:
    int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48 整个数组的大小
	printf("%d\n", sizeof(a[0][0]));//4 首元素的大小
	printf("%d\n", sizeof(a[0]));//16 a[0]表示第一行数组名,计算第一行的大小
	printf("%d\n", sizeof(a[0]+1));//4 a[0]为首元素地址,表示第一行第一个元素地址,+1为第一行第二个元素地址
	printf("%d\n", sizeof(*(a[0]+1)));//4
	printf("%d\n", sizeof(a+1));// 4 a为第一行地址,+1为第二行地址
	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 某一行的数组名,某一行的大小

总结:
1.sizeof(数组名),数组名表示整个数组,计算整个数组的大小
2.&数组名,数组名表示整个数组,取整个数组的地址
3.除以上两条之外所有的数组名表示首元素的地址

  • sizeof和strlen的区别
    1、sizeof操作符的结果类型是size_t,在头文件中typedef为unsigned int 类型,保证能容纳实现所建立的最大对象的字节大小
    2、sizeof是运算符,而strlen是函数
    3、sizeof可以用类型做参数,而strlen只能用char *做参数,必须以‘\0’结尾,sizeof也可以用函数做参数,例如:
long f();
printf("%d\n",sizeof(f()));

输出结果是sizeof(long),即为4
4、数组作为sizeof的参数不用退化,而传递给strlen就退化为指针
5、大多数编译程序在编译期间将sizeof已经计算过了,是类型或者是变量的长度,即sizeof(n)可以用来定义数组维数,例如:

char arr[20]="0123456789";
int a=strlen(arr);//a=10
int b=sizeof(arr);//b=20

6、strlen的结果在运行时计算出来,用来计算字符串的长度,不是类型占用内存的大小
7、当适用于一个结构类型或变量,sizeof返回实际的大小,当适用一个静态空间的数组,sizeof归还全部数组的尺寸;sizeof操作符不能返回动态地被分配的数组或外部的数组的尺寸。

指针笔试题

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d %d\n", *(a + 1), *(ptr - 1));
	//结果为2,5
	system("pause");
	return 0;
}

*(a+1)中a表示首元素地址,a+1为第二个元素地址,解引用为第二个元素2;ptr存&a+1,ptr-1表示向前挪动一个位置为5的地址,解引用为5,结果为2,5。

struct Test
{
	int Num;
	char* pcNum;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p的值为0x100000
//结构体的大小为20个字节
int main()
{
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	system("pause");
	return 0;
}

第一个表示p为结构体指针变量,+1为+20,结果为16进制0x100014,第二个表示p被强制转换为无符号长整形,整形+1为+1,结果为0x100001,第三个表示p被强制转换为无符号整形指针,+1为+4,结果为0x100004。

    int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);,
	int* ptr2 = (int*)((int)a + 1);
	printf("%x %x\n", ptr1[-1], *ptr2);

&a+1表示跳过一个数组到4的后面的地址,ptr1存这个地址;数组在计算机中是以小端放的,即a[4]为01 00 00 00 |02 00 00 00 | 03 00 00 00 | 04 00 00 00,a为首元素地址,强制类型转换为整形,+1到01后面的00的地址,即为ptr2为00 00 00 02;ptr1[-1]为*(ptr1-1),结果为4,*ptr2输出整形为00 00 00 02,以小端输出为02 00 00 00,即为2 00 00 00。

    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式,结果为1,3,5,数组只放了1,3,5
 	int*p;
	p = a[0];//第一行的数组名,放第一行第一个元素的地址
	printf("%d\n", p[0]);//数组的第一个元素 1
    int a[5][5];
	int(*p)[4];
	p = a;//a[5][5]第一行的地址
	printf("%p %d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	

结果为 FF FF FF FC,-4;-4在计算机中的补码为11111111 11111111 11111111 11111100,转换为16进制为FF FF FF FC;p[4][2]等价于*((p+4)+2),如下:p指向数组第一行的地址,即a[0]的地址;
因为p为元素为整形的数组指针, p+4表示跳过四个整形数组,指向a[3][1],
(p+4)为a[3][1],* ( *(p+4)+2)为a[3][3],则&p[4][2]-&a[4][2]=-4,-4的补码为11111111 11111111 11111111 11111100,表示为地址为FF FF FF FC。

    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);//&aa+1为跳过整个数组10后面的地址,为ptr1
	int* ptr2 = (int*)(aa + 1);//aa+1为第二行的地址,为ptr2
	printf("%d %d\n", *(ptr1 - 1), *(ptr2 - 1));//*(ptr1-1)为10,*(ptr2-1)为5
    char* a[] = { "work", "at", "alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);//结果为at

结果为at,a为一个指针数组,数组的每个元素为指向各个字符串第一个字符的指针,pa时一个二级指针,指向a的第一个字符地址,pa++,表示跳过一个字符指针,*pa为at。

    char* c[] = { "ENTER", "NEW", "POINT", "FIRST" };
	char** cp[] = { c + 3, c + 2, c + 1, c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);//POINT
	printf("%s\n", *--*++cpp + 3);//上一个++cpp会产生副作用,结果为ER
	printf("%s\n", *cpp[-2] + 3);//上一个++cpp会产生副作用,结果为ST
	printf("%s\n", cpp[-1][-1] + 1);//上一个++cpp会产生副作用,结果为EW

c为一个指针数组,数组的元素为指向各个字符串首元素的指针,cp为二级指针数组,数组元素分别为指向c的第4个元素指针,指向c的第3个元素的指针,指向c的第2个元素指针,指向c的第1个元素指针,;cpp为三级指针数组,数组元素为指向cp首元素的指针;则**++cpp表示先++,在两次解引用为POINT,++cpp+3表示先++,再解引用,再–,再解引用,再+3,因为上一个++会产生副作用,结果为ER;*cpp[-2]+3表示 *( *(cpp-2))+3,因为上一个++cpp会产生副作用,结果为ST,cpp[-1]-1]+1表示 *( *(cpp-1)-1),之前++产生副作用,结果为EW。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值