史上最强C语言教程----指针(笔试题1)

x33g5p2x  于2022-01-09 转载在 其他  
字(6.5k)|赞(0)|评价(0)|浏览(141)
  1. 指针和数组笔试题及解析

9.1一维数组

9.1.1 一维整型数组

9.1.2 一维字符数组

9.2 二维数组

9. 指针和数组笔试题及解析

9.1一维数组

9.1.1 一维整型数组

#include<stdio.h>
int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16--计算的是数组总大小,单位是字节
	//数组名代表数组首元素的地址时,有两个意外
	//1.sizeof(数组名)  注意:里面必须只有数组名,才能代表整个数组 
	//2.&数组名
	printf("%d\n", sizeof(a + 0));//4/8--此处的数组名代表首元素的地址,+0之后仍是首元素的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(*a));//4--a是首元素的地址,*a即是首元素,即int型
	printf("%d\n", sizeof(a + 1));//4/8--数组名是首元素的地址,a+1即是第二个元素的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(a[1]));//4--第二个元素,即int型
	printf("%d\n", sizeof(&a));//4/8--整个数组的地址,数组的地址也是地址,地址的大小是4/8个字节,类型是数组指针
	printf("%d\n", sizeof(*&a));//&a是数组的地址,对数组的地址进行解引用就是数组,即求的是一个数组的大小,与sizeof(a)等价
	printf("%d\n", sizeof(&a + 1));//4/8--&a+1是跳过一个数组的大小,即下一个单位a数组的地址,但其本质上仍然是地址
	printf("%d\n", sizeof(&a[0]));//4/8--数组首元素的地址
	printf("%d\n", sizeof(&a[0] + 1));//4/8--数组第二个元素的地址
	return 0;
}

运行截图:

很明显,与我们上面进行解析的一样! 下面是一个帮助理解的图:

9.1.2 一维字符数组

(1)以{}定义的一维字符数组

#include<stdio.h>
int main()
{
	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));//6--此处sizeof计算的是数组的大小,数组有6个char类型的元素,即6个字节
	printf("%d\n", sizeof(arr + 0));//4/8--arr是数组首元素的地址,arr+1仍为数组首元素的地址,地址的大小为4/8个字节
	printf("%d\n", sizeof(*arr));//1--arr是数组首元素的地址,*a即为数组首元素,计算的是数组首元素的大小
	printf("%d\n", sizeof(arr[1]));//1--计算的是数组首元素的大小
	printf("%d\n", sizeof(&arr));//4/8--&arr取的是数组的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(&arr + 1));//4/8--&arr是数组的地址,&arr+1是跳过一个单位a数组后的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(&arr[0] + 1));//4/8--数组第二个元素的地址
	printf("%d\n", strlen(arr));//随机值--strlen遇到字符串的结束标志'\0'才会停止,在这个字符数组中没有'\0',后面内存中放的我们并不知道
	printf("%d\n", strlen(arr + 0));//随机值--与上一个一样
	printf("%d\n", strlen(*arr));//程序崩溃--*arr = 'a',此处把97(字符a的ascii码值)当成是一个地址,此处将会发生程序崩溃的现象,因为非法访问内存地址
	printf("%d\n", strlen(arr[1]));//程序崩溃--非法访问内存地址,造成程序崩溃,与上一个一样
	printf("%d\n", strlen(&arr));//随机值--与strlen(arr)和strlen(arr+0)一样,因为数组的地址和数组首元素的地址在数值上是一样的
	printf("%d\n", strlen(&arr + 1));//随机值--但是与前面的strlen(&arr)随机值有一个固定的差值,比那个小6
	printf("%d\n", strlen(&arr[0] + 1));//随机值--但是与前面的strlen(&arr)随机值有一个固定的差值,比那个小1
	//strlen(arr+0)==strlen(arr)==strlen(&arr)
	//strlen(&arr+1)==strlen(arr)-6
	//strlen(&arr[0]+1)==strlen(arr)-1
	//strlen是从()中的地址开始,无论这个地址是数组的地址还是数组首元素的地址还是数组中任意一个元素的地址,都是从该地址开始,一个字节记作是一个
	//字符,直到遇到'\0'才会停止,结果即为从地址开始到'\0'中间的字节数(字符数)
	return 0;
}

此处就不放运行截图了,因为程序发生了崩溃现象!

(2)以“”定义的一维字符数组

1‘用字符数组进行存储

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//7--数组所占空间的大小,还有一个是字符串的结束标志'\0'
	printf("%d\n", sizeof(arr + 0));//4/8--arr是数组首元素的地址,+0后不会发生改变仍为数组首元素的地址,地址的大小是4或者8个字节
	printf("%d\n", sizeof(*arr));//1--arr是数组首元素的地址,对其进行解引用之后就是数组首元素,即一个字符,占一个字节
	printf("%d\n", sizeof(arr[1]));//1--数组的第二个元素,即一个字符,占一个字节
	printf("%d\n", sizeof(&arr));//4/8--数组的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(&arr + 1));//4/8--跳过一个单位数组后的地址,地址的大小是4或者8个字节
	printf("%d\n", sizeof(&arr[0] + 1));//4/8--数组第二个元素的地址
	printf("%d\n", strlen(arr));//6--从数组首元素的地址到'\0'总共出现6个字符,'\0'不算在内
	printf("%d\n", strlen(arr + 0));//6--数组名代表首元素的地址,加0后依旧是数组首元素的地址,跟上面的一样,6个字符
	printf("%d\n", strlen(*arr));//程序崩溃--非法访问内存地址,因为访问了字符'a'的ascii码值作为的地址,行为非法
	printf("%d\n", strlen(arr[1]));//程序崩溃--非法访问内存地址,因为访问了数组第二个元素字符'b'的ascii码值作为的地址,行为非法
	printf("%d\n", strlen(&arr));//6--&arr是数组的地址,数组的地址和数组首元素的地址在数值上是完全一样的,所以与strlen(arr)结果是完全一样的
	printf("%d\n", strlen(&arr + 1));//随机值--因为跳过了一个数组后的地址,后面的元素不确定,即不确定'\0'出现在什么位置,所以结果随机
	printf("%d\n", strlen(&arr[0] + 1));//5--数组第二个元素'b'的地址开始到'\0'的字符的数目,'\0'不计入在内,总共5个字符
	return 0;
}

2’用字符指针进行存储

#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));//4/8--计算的是指针变量p的大小,p中存储的是a的地址,地址的大小为4/8个字节
	printf("%d\n", sizeof(p + 1));//4/8--p中存储的是a的地址,p+1就是b的地址,地址的大小为4/8个字节
	printf("%d\n", sizeof(*p));//1--p存储的是字符a的地址,对其进行解引用得到的是就是字符a
	printf("%d\n", sizeof(p[0]));//1--p[0]就是字符a 注意:p[0]==*(p+0)=='a'
	printf("%d\n", sizeof(&p));//4/8--&p就是指针变量p的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(&p + 1));//4/8--指针变量p的地址加1,p的类型是char *p,&p的类型是char **p,&p+1就是跳过一个字符指针的大小,结果仍然是地址
	printf("%d\n", sizeof(&p[0] + 1));//4/8--结果就是字符'b'的地址,地址的大小就是4/8个字节
	printf("%d\n", strlen(p));//6--p中存储的是a的地址,从a到'\0',不把'\0'计入在内总共有6个字符
	printf("%d\n", strlen(p + 1));//5--p中存储的是a的地址,p的类型是char *,跳过一个char元素的地址,即'b'的地址
	printf("%d\n", strlen(*p));//程序崩溃--非法访问以'a'的ascii码值作为的地址
	printf("%d\n", strlen(p[0]));//程序崩溃--非法访问以'a'的ascii码值作为的地址
	printf("%d\n", strlen(&p));//随机值--此处是从指针变量p的地址开始,后面的值我们并不确定
	printf("%d\n", strlen(&p + 1));//随机值--&p的类型是char**,&p+1就是指针变量p的地址跳过一个char*类型(指针类型,大小为4/8个字节),此处类似上一个,地址值和地址后面的值我们都不清楚
	printf("%d\n", strlen(&p[0] + 1));//5--此处就是从第二个元素'b'的地址开始的
	return 0;
}

此处进行解释一下strlen(&p),因为此处是从p的地址开始的,而p的地址是00 f7 7b d0(左边是高地址位,右边是低地址位),在这个地方,此时是16进制的,一个16进制位代表4个bit位,8个bie位代表一个字节,即上面的2位才是1个字节,而strlen()函数是从低地址位开始的,所以d0 7b f7总共是三个非0的字节,所以上面的结果才是3个字节。

9.2 二维数组

#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48--求的是整个数组所占空间的大小,总共12个整型元素,12*4=48个字节
	printf("%d\n", sizeof(a[0][0]));//4--数组第一行第一个元素的大小
	printf("%d\n", sizeof(a[0]));//16--a[0]是第一行的数组名,因为数组a是由三个一维数组组成的,这三个一维数组的数组名分别是a[0]、a[1]、a[2]
	//而当数组名单独出现在sizeof后面的括号中时,代表的是整个一维数组,所以在此时就是整个一维数组a[0],有4个元素
	printf("%d\n", sizeof(a[0] + 1));//4/8--数组名代表首元素的地址,a[0]表示的是第一行的数组名,此处表示的是第一行第一个元素的首地址,加1后是第一行第二个元素的地址
	printf("%d\n", sizeof(*(a[0] + 1)));//4--其实就是对前面这一个进行解引用,解引用后就是第一行第二个元素
	printf("%d\n", sizeof(a + 1));//4/8--此处a是数组名,但是a既不是sizeof(数组名),也不是&数组名,a是数组首元素的地址,二维数组的元素即是一维数组,此处a即是第一行的地址,加1后即为第二行的地址
	printf("%d\n", sizeof(*(a + 1)));//16--此处a+1是第二行的地址,也是第二行的数组名,此处等价于sizeof(a[1]),所以对其解引用后就是第二行的所有元素,即4*4=16
	printf("%d\n", sizeof(&a[0] + 1));//4/8--a[0]是数组第一行的数组名,&a[0]就是第一行的地址,加1后就是第二行的地址
	printf("%d\n", sizeof(*(&a[0] + 1)));//16--对第二行的地址进行解引用之后得到的就是第二行的所有元素
	printf("%d\n", sizeof(*a));//16--a是首元素的地址,*a就是第一行,所以解引用后就是第一行的所有元素
	printf("%d\n", sizeof(a[3]));//16--第四行的数组名,a[3]是第四行数组,有四个整型元素,所以是16个字节
	//注意:最后这个为什么不会发生越界访问的错误?因为在sizeof括号中的表达式不参与运算,也就是不进行访问,既然都没有进行访问,所以就不会出现越界访问的错误了
	return 0;
}

总结:

数组名的意义:

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

相关文章