【C语言进阶】指针和数组笔试题详细解析

【C语言进阶】


九、指针和数组笔试题详细解析

1 一维数组

示例

#include<stdio.h>

int main()
{
	//一维数组

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

	printf("%d\n", sizeof(arr));
	//sizeof(arr)表示整个数组的大小:4*4=16
	printf("%d\n", sizeof(arr + 0));
	//arr+0表示数组首元素的地址,地址的大小:4/8
	printf("%d\n", sizeof(*arr));
	//arr表示数组首元素的地址,*arr表示数组首元素,int型数据的大小:4
	printf("%d\n", sizeof(arr + 1));
	//arr+1表示数组下标为1的元素的地址(第二个元素的地址),地址的大小:4/8
	printf("%d\n", sizeof(arr[1]));
	//arr[1]表示数组下标为1的元素(第二个元素),int型数据的大小:4
	printf("%d\n", sizeof(&arr));
	//&arr表示整个数组的地址,地址的大小:4/8
	printf("%d\n", sizeof(*&arr));
	//*&arr表示数组名:arr;sizeof(arr)表示整个数组的大小:16
	printf("%d\n", sizeof(&arr + 1));
	//&arr+1表示向后跳过一个数组类型大小的地址,地址的大小:4/8
	printf("%d\n", sizeof(&arr[0]));
	//&arr[0]表示数组首元素的地址,地址的大小:4/8
	printf("%d\n", sizeof(&arr[0] + 1));
	//&arr[0]+1表示下标为1元素的地址(第二个元素的地址),地址的大小:4/8

	/*
	*	x86		x64
	*	16		16
	*	4		8
	*	4		4
	*	4		8
	*	4		4
	*	4		8
	*	16		16
	*	4		8
	*	4		8
	*	4		8
	*/

	return 0;
}


2 字符数组

2.1 用初始化列表初始化的字符数组

示例

#include<stdio.h>

#include<string.h>
int main()
{
	//字符数组 - 用初始化列表(字符)初始化的字符数组

	char ch[] = { 'a','b','c','d','e','f' };//a b c d e f

	//siezof:以字节为单位计算对象的大小

	printf("%d\n", sizeof(ch));
	//sizeof(ch)表示整个数组的大小:1*6=6
	printf("%d\n", sizeof(ch + 0));
	//ch+0表示数组首元素的地址,地址的大小:4/8
	printf("%d\n", sizeof(*ch));
	//*ch表示数组首元素,char型数据的大小:1
	printf("%d\n", sizeof(ch[1]));
	//ch[1]表示数组下标为1的元素(第二个元素),char型数据的大小:1
	printf("%d\n", sizeof(&ch));
	//&ch表示整个数组的地址,地址的大小:4/8
	printf("%d\n", sizeof(&ch + 1));
	//&ch+1表示向后跳过一个数组类型大小的地址,地址的大小:4/8
	printf("%d\n", sizeof(&ch[0] + 1));
	//&ch[0]+1表示数组下标为1元素的地址(第二个元素的地址),地址的大小:4/8

	printf("\n");
	/*
	*	x86		x64
	*	6		6
	*	4		8
	*	1		1
	*	1		1
	*	4		8
	*	4		8
	*	4		8
	*/


	//strlen:求字符串长度的库函数,统计的是字符串中'\0'(不包括)之前的字符个数;
	//如果没有'\0',会越过字符数组向后一直寻找,直到遇到'\0'
	//strlen的参数为地址

	printf("%d\n", strlen(ch));
	//ch表示数组首元素的地址,该字符数组中没有'\0',strlen会越过数组向后继续寻找,直到遇见'\0'
	//最后统计的字符数是:随机值
	printf("%d\n", strlen(ch + 0));
	//ch+0表示数组首元素的地址,该字符数组中没有'\0',strlen会越过数组向后继续寻找,直到遇见'\0'
	//最后统计的字符数是:随机值
	printf("%d\n", strlen(*ch));//error
	//*ch表示数组首元素'a',字符'a'的ASCII码值为97,将97作为地址访问,向后统计字符个数
	//error,非法访问内存地址
	printf("%d\n", strlen(ch[1]));//error
	//ch[1]表示啊数组首元素'a',字符'a'的ASCII码值为97,将97作为地址访问,向后统计字符个数
	//error,非法访问内存地址
	printf("%d\n", strlen(&ch));
	//&ch表示整个数组的地址,与数组首元素地址的值相同,传递给strlen依然是从数组首元素的地址处向后找'\0
	//最后统计的字符数是:随机值
	printf("%d\n", strlen(&ch + 1));
	//&ch+1表示向后跳过一个数组类型大小的地址,与传递&ch和ch所计算的大小差一个数组长度(6)
	//最后统计的字符数是:随机值
	printf("%d\n", strlen(&ch[0] + 1));
	//&ch[0]+1表示第二个元素的地址,与传递&ch和ch所计算的大小差1
	//最后统计的字符数是:随机值

	return 0;
}


2.2 用字符串初始化的字符数组

示例

#include<stdio.h>

#include<string.h>
int main()
{
	//字符数组 - 用字符串初始化的字符数组

	char ch[] = "abcdef";//a b c d e f \0

	//siezof:以字节为单位计算对象的大小

	printf("%d\n", sizeof(ch));
	//整个数组的大小:1*7=7
	printf("%d\n", sizeof(ch + 0));
	//首元素地址的大小:4/8
	printf("%d\n", sizeof(*ch));
	//数组首元素的大小:1
	printf("%d\n", sizeof(ch[1]));
	//数组第二个元素的大小:1
	printf("%d\n", sizeof(&ch));
	//数组类型的地址:4/8
	printf("%d\n", sizeof(&ch + 1));
	//数组类型的地址:4/8
	printf("%d\n", sizeof(&ch[0] + 1));
	//数组第二个元素的地址:4/8

	printf("\n");
	/*
	*	x86		x64
	*	7		8
	*	4		8
	*	1		1
	*	1		1
	*	4		8
	*	4		8
	*	4		8
	*/


	//strlen:求字符串长度的库函数,统计的是字符串中'\0'(不包括)之前的字符个数;
	//如果没有'\0',会越过字符数组向后一直寻找,直到遇到'\0'
	//strlen的参数为地址

	printf("%d\n", strlen(ch));
	//<6> -- 从首元素的地址处向后找\0
	printf("%d\n", strlen(ch + 0));
	//<6> -- 从首元素的地址处向后找\0
	printf("%d\n", strlen(*ch));//error
	//<非法访问>
	printf("%d\n", strlen(ch[1]));//error
	//<非法访问>
	printf("%d\n", strlen(&ch));
	//<6> -- 从首元素的地址处向后找\0
	printf("%d\n", strlen(&ch + 1));
	//<随机值> -- 从'\0'(数组末尾元素)之后的位置开始找\0
	printf("%d\n", strlen(&ch[0] + 1));
	//<5> -- 从第2个元素的地址处向后找\0

	/*
	*	6
	*	6
	*	6
	*	随机值
	*	5
	*/

	return 0;
}


2.3 指向常量字符串的字符指针

示例

#include<stdio.h>

#include<string.h>
int main()
{
	//字符数组 - 指向常量字符串的字符指针

	char* p = "abcdef";//字符指针p指向常量字符串,指针变量存放的是首字符'a'的地址

	//siezof:以字节为单位计算对象的大小

	printf("%d\n", sizeof(p));
	//p的值是'a'的地址,地址的大小:4/8
	printf("%d\n", sizeof(p + 1));
	//p+1表示'b'的地址,地址的大小:4/8
	printf("%d\n", sizeof(*p));
	//*p表示字符'a',一个char型数据的大小:1
	printf("%d\n", sizeof(p[0]));;
	//p[0]表示字符'a',一个char型数据的大小:1
	printf("%d\n", sizeof(&p));
	//指针变量p的地址,地址的大小:4/8
	printf("%d\n", sizeof(&p + 1));
	//&p+1是指针变量p之后位置的地址,地址的大小:4/8
	printf("%d\n", sizeof(&p[0] + 1));
	//&p[0]+1表示字符'b'的地址,地址的大小:4/8

	printf("\n");
	/*
	*	x86		x64
	*	4		8
	*	4		8
	*	1		1
	*	1		1
	*	4		8
	*	4		8
	*	4		8
	*/


	//strlen:求字符串长度的库函数,统计的是字符串中'\0'(不包括)之前的字符个数;
	//strlen的参数为地址
	
	//要明确strlen从何地址处开始向后找\0
	printf("%d\n", strlen(p));			
	// <6>-- 从首元素的地址处向后找\0
	printf("%d\n", strlen(p + 1));		
	// <5> -- 从第二个元素的地址处向后找\0
	printf("%d\n", strlen(*p));//error		
	// <非法访问>
	//printf("%d\n", strlen(p[0]));//error
	// <非法访问>
	printf("%d\n", strlen(&p));			
	// 随机值 -- 从指针变量的地址处向后找\0
	printf("%d\n", strlen(&p + 1));		
	// 随机值 -- 从指针变量后一个类型大小的地址处向后找\0
	printf("%d\n", strlen(&p[0] + 1));	
	// <5> -- 从第二个元素开始向后找\0

	/*
	*	6
	*	5
	*	随机值
	*	随机值
	*	5
	*/

	return 0;
}


3 二维数组

示例

#include<stdio.h>

int main()
{
	//二维数组

	int arr[3][4] = { 0 };

	printf("%d\n", sizeof(arr));
	//整个二维数组的大小(int[3][4]):3*4*4=48
	printf("%d\n", sizeof(arr[0][0]));
	//二维数组首元素(一维数组)的首元素,即第一行第一列元素的大小(int):4
	printf("%d\n", sizeof(arr[0]));
	//二维数组首元素(第一行、一维数组的数组名)的大小(int[4]):4*4=16
	printf("%d\n", sizeof(arr[0] + 1));
	//arr[0]表示二维数组首元素(一维数组数组名),+1表示第1行第2个元素的地址,地址的大小:4/8

	printf("\n");
	/*
	*	x86		x64
	*	48		48
	*	4		4
	*	16		16
	*	4		8
	*/

	printf("%d\n", sizeof(*(arr[0] + 1)));
	//第一行第二个元素(arr[0][1])的大小(int):4
	printf("%d\n", sizeof(arr + 1));
	//arr表示二维数组名,是二维数组首元素arr[0]的地址;
	//arr+1表示二维数组第二个元素的地址(&arr[1]):4/8
	printf("%d\n", sizeof(*(arr + 1)));
	//*(arr+1)相当于*&arr[1],arr[1]表示二维数组第二个元素,是一个数组名;
	//sizeof(数组名)计算的是整个数组的大小(int[4]):4*4=16
	printf("%d\n", sizeof(&arr[0] + 1));
	//&arr[0]表示二维数组首元素的地址(一维数组的地址)
	//+1表示向后跳过一个数组类型的大小(int*[4]),地址的大小:4/8
	printf("%d\n", sizeof(*(&arr[0] + 1)));
	//对一个数组类型解引用,获得的是整个一维数组;
	//*(&arr[0]+1)相当于arr[1],相当于二维数组第二个元素(一维数组数组名)
	//整个一维数组的大小(int[4]):4*4=16
	printf("%d\n", sizeof(*arr));
	//*arr表示二维数组首元素,即一个一维数组的大小(int[4]):4*4=16
	printf("%d\n", sizeof(arr[3]));
	//一个一维数组数组名,表示整个一维数组的大小(int[4]):4*4=16

	/*
	*	x86		x64
	*	4		4
	*	4		8
	*	16		16
	*	4		8
	*	16		16
	*	16		16
	*	16		16
	*/

	return 0;
}


4 数组名的意义

1.sizeof(数组名) :计算的是整个数组的大小,或者说是计算一个数组类型的大小

2.&数组名 :取出的是整个数组的地址,或者说是一个数组类型的地址

3.其他地方的数组名都表示首元素的地址


5 再探 sizeof 操作符

sizeof() 只会的分析括号内对象的类型,然后给出大小,不会实际访问内存去计算。

代码示例

#include<stdio.h>

int main()
{
	//再探sizeof操作符

	int a = 3;
	short b = 4;

	//sizeof在编译期间就获取了对象的大小,
	//不会在程序运行期间实际访问内存去计算
	printf("%d\n", sizeof(b = a + 2));//2
	printf("%d\n", sizeof(b));//2

	return 0;
}

解释说明

1 sizeof 在编译期间就获取了对象的大小

注意:表达式的2个属性

​ 1.值属性: 表达式都会有一个结果值

​ 2.类型属性b = a + 2 -> short


总结:

  本节给出了指针与数组相关笔试题的实例和解析,对指针与数组有了更加深入的理解。


感谢您的阅读!如有任何错误,欢迎您的批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值