C语言 --- 指针(5)

目录

一.sizeof和strlen对比

1.sizeof

2.strlen

3.strlen 和sizeof的对比

二.数组和指针笔试题目详解

 回顾:数组名的理解

1.一维数组

2.字符数组 

代码1:

 代码2:

 代码3:

代码4:

代码5:

代码6:

3.二维数组 

总结 


一.sizeof和strlen对比

1.sizeof

sizeof既是一种关键字也是一个操作符。sizeof的作用是计算变量和类型的所占内存空间的大小,单位是字节,返回size_t类型的值。sizeof只关注所占用内存空间的大小,不在乎内存中存放的什么数据。

比如:

#include<stdio.h>
int main()
{
    int a = 10;
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof a );
    printf("%d\n",sizeof(int));
    
    return 0;
}

sizeof在使用时,可以不用括号,这证明了它不是一个函数,但是在计算类型比如int就不行,必须加括号。

打印结果都是4,size_t类型的值应该用%zd打印,但是这里也可以使用%d,只不过编译器会发出警告,但是影响不大。

sizeof不关注括号中的数据,只关注存放内存的大小。比如:

#include<stdio.h>
int main()
{
	int a = 10;
	int size = sizeof(a++);
	printf("%d\n",size);
	printf("%d\n",a);
	return 0;
}

输出结果是4  10

很明显sizeof括号中的表达式是没有计算的。 

2.strlen

strlen是C语言库函数,在使用时需要包含头文件<string.h>

函数原型:

size_t strlen(const char *str);

这个函数会返回字符串中字符数,但是不包括\0,也就是返回的是\0之前的字符数。如果没有\0就会出现越界查找的情况。

比如:

#include<stdio.h>
int main()
{
    char arr1[] = {'a','b','c'};
    char arr2[] ="abc" ;
    printf("%d\n",strlen(arr1));
    printf("%d\n",strlen(arr2));
    printf("%d\n",sizeof(arr1));
    printf("%d\n",sizeof(arr2));
    
    return 0;
}

打印结果是 随机值 3 3 4.

第一个是随机值的原因就是没有\0,strlen会一直查找直到遇到\0才终止。

第二个因为是常量字符串,包含\0,所以是3。

第三个计算的是数组arr1中所占内存的大小,只有三个字符,也就是3个字节。

第四个arr2中有\0,所以是4个字节。

3.strlen 和sizeof的对比

sizeof strlen
  1. sizeof是操作符。
  2. sizeof计算的是操作数所占内存空间的大小,单位是字节。
  3. 不关注内存中存放的什么数据。
  1. strlen是库函数,使用的头文件是<string.h>。
  2. strlen是求字符串长度的,统计的是\0之前的字符个数。
  3. strlen关注内存中是否有\0,如果没有\0,就会继续往前找,可能会出现越界的情况。

二.数组和指针笔试题目详解

 回顾:数组名的理解

 数组名是数组首元素的地址。

但是有两个的特殊情况

  1. sizeof(数组名) ,sizeof中单独放数组名,这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节。
  2. &数组名,这里的数组名代表的是整个数组,&取出的是整个数组的地址。(整个数组的地址虽然和数组首元素的地址是相同的,但是指针变量的类型是不同的。)

1.一维数组

#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };

	printf("%d\n", sizeof(a));//1
	printf("%d\n", sizeof(a + 0));//2
	printf("%d\n", sizeof(*a));//3
	printf("%d\n", sizeof(a + 1));//4
	printf("%d\n", sizeof(a[1]));//5
	printf("%d\n", sizeof(&a));//6
	printf("%d\n", sizeof(*&a));//7
	printf("%d\n", sizeof(&a + 1));//8
	printf("%d\n", sizeof(&a[0]));//9
	printf("%d\n", sizeof(&a[0] + 1));//10

	return 0;
}
序号 解析 答案
1  a是数组名,sizeof中单独放数组名,计算的是整个数组的大小,单位字节。 16
2 sizeof中没有单独放数组名a,所以这里的数组名就是数组首元素的地址,地址就是指针变量。在不同环境下大小不同。 4 || 8
3 a是数组首元素的地址,解引用后得到数组首元素。所以计算的是整形变量的大小。 4
4 a表示数组首元素的地址,地址就是指针,类型是int*,指针加1跳过4个字节,也就是一个整形元素,也就是第二个元素的地址。 4 || 8
5 a[1]表示数组第二个元素 4
6 &a是整个数组的地址,地址就是指针变量. 4 || 8
7 &a是整个数组的地址,解引用后就是整个数组。所以sizeof计算的是整个数组的大小(&和*可以相互抵消 16
8 &a是整个数组的地址,+1跳过了整个数组,虽然这个地址并没有指向这个数组了,但是我们并没有越界访问,所以不影响sizeof计算这个指针变量的大小。 4 || 8
9 &a[0]得到的是数组首元素的地址. 4 || 8
10 &a[0]+1,跳过一个元素,得到的是数组第二个元素的地址。 4 || 8

2.字符数组 

代码1:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7
序号 解析 答案
1 arr单独放在sizeof中,计算的是整个数组的大小。单位字节 6
2 arr没有单独放在数组中,arr表示的是数组首元素的地址 4 || 8
3 arr表示的是数组首元素的地址,解引用后得到的是数组首元素。 1
4 arr[1]表示数组首元素。 1
5 &arr表示整个数组的地址,地址就是指针变量 4 || 8
6

&a是整个数组的地址,+1跳过了整个数组,虽然这个地址并没有指向这个数组了,但是我们并没有越界访问,所以不影响sizeof计算这个指针变量的大小。

4 || 8
7 &arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址 4 || 8

 代码2:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr+0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr+1));//6
printf("%d\n", strlen(&arr[0]+1));//7
序号 解析 答案
1 arr是数组首元素的地址,strlen计算的是'\0'之前的字符个数,但是这个数组中并没有'\0',所以会出现越界的情况,故无法出现准确的值的情况。 随机值
2 这里的arr也是数组首元素的地址,+0并没有跳过任何字节,与序号1同理也是不确定情况。(两个值应该是一样的) 随机值
3 strlen的参数是const char *类型的。*arr得到的是数组首元素,将这个作为参数传给strlen是不行的,这里程序会崩溃。 error
4 arr[1]表示数组第二个元素,将其作为参数传给strlen是不行的。 error
5 &arr表示整个数组的地址,虽然是一个数组指针变量,但是传参会进行强制类型转换为char*类型,值和数组首元素的地址相同,所以和序号1和2相同,值一样的。 随机值
6

&a是整个数组的地址,+1跳过了整个数组,也就是跳过了6个字节。但是因为没有'\0',也会出现随机的情况

随机值(比序号125小6)
7 &arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,只跳过了1个字节。 随机值(比序号125小1)

输出结果:(以下是随机值,不是特定情况。)

 

序号3和4已被注释掉了。

 代码3:

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7
序号 解析 答案
1 sizeof(数组名),计算的是整个数组的大小,字符串末尾是有一个'\0'的,只不过没有显示出来,我们可以通过调试观察,所以这个字符串中有7个字符。 7
2 这里的arr也是数组首元素的地址,+0并没有跳过任何字节,是一个指针变量。 4 || 8
3 *arr的到的数组首元素。 1
4 arr[1]表示数组第二个元素. 1
5 &arr表示整个数组的地址,是一个指针变量。 4 || 8
6

&a是整个数组的地址,+1跳过了整个数组,但是还是一个指针变量

4 || 8
7 &arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,是一个指针变量 4 || 8

序号1:

我们可以看到数组中分别放着不同的字符,字符前面是它们的ASCII码值,arr[6],也就是数组的第7个元素,存放着'\0'字符。

代码4:

char arr[] = "abcdef";
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr+0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr+1));//6
printf("%d\n", strlen(&arr[0]+1));//7
序号 解析 答案
1 sizeof计算的是'\0'之前的地址,有6个字符 6
2 sizeof计算的是'\0'之前的地址,有6个字符 6
3 *arr的到的数组首元素。不应该作为参数传给strlen error
4 arr[1]表示数组第二个元素.不应该作为参数传给strlen error
5 &arr表示整个数组的地址,sizeof计算的是'\0'之前的地址,有6个字符. 6
6

&a是整个数组的地址,+1跳过了整个数组,故不知道什么时候会遇到'\0',所以是个随机值

随机值
7 &arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,从第二个开始到'\0',有5个字节。 5

输出结果:

序号6就是经过了16个字符才遇到'\0',error情况已经注释掉了。

代码5:

char *p = "abcdef";
printf("%d\n", sizeof(p));//1
printf("%d\n", sizeof(p+1));//2
printf("%d\n", sizeof(*p));//3
printf("%d\n", sizeof(p[0]));//4
printf("%d\n", sizeof(&p));//5
printf("%d\n", sizeof(&p+1));//6
printf("%d\n", sizeof(&p[0]+1);//7
序号 解析 答案
1 sizeof计算的是'\0'之前的地址,有6个字符 6
2 sizeof计算的是'\0'之前的地址,有6个字符 6
3 *arr的到的数组首元素。不应该作为参数传给strlen error
4 arr[1]表示数组第二个元素.不应该作为参数传给strlen error
5 &arr表示整个数组的地址,sizeof计算的是'\0'之前的地址,有6个字符. 6
6

&a是整个数组的地址,+1跳过了整个数组,故不知道什么时候会遇到'\0',所以是个随机值

随机值
7 &arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,从第二个开始到'\0',有5个字节。 5

代码6:

char *p = "abcdef";
printf("%d\n", strlen(p));//1
printf("%d\n", strlen(p+1));//2
printf("%d\n", strlen(*p));//3
printf("%d\n", strlen(p[0]));//4
printf("%d\n", strlen(&p));//5
printf("%d\n", strlen(&p+1));//6
printf("%d\n", strlen(&p[0]+1));//7
序号 解析 答案
1 sizeof计算的是'\0'之前的地址,有6个字符 6
2 sizeof计算的是'\0'之前的地址,+1后跳过一个字节,也就是一个元素,有5个字符 5
3 *p的到的数组首元素。不应该作为参数传给strlen error
4 p[0]表示数组第一个元素.不应该作为参数传给strlen error
5 &p表示字符指针的地址,sizeof计算的是'\0'之前的地址,会产生随机值 随机值
6

&p是字符指针的地址,加1 跳过4 || 8个字节,故不知道什么时候会遇到'\0',所以是个随机值

随机值
7 &p[0]表示首首字符的地址,+1跳过一个元素,表示第二个字符的地址,从第二个开始到'\0',有5个字节。 5

输出结果:

3.二维数组 

int a[3][4] = {0};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a[0][0]));//2
printf("%d\n",sizeof(a[0]));//3
printf("%d\n",sizeof(a[0]+1));//4
printf("%d\n",sizeof(*(a[0]+1)));//5
printf("%d\n",sizeof(a+1));//6
printf("%d\n",sizeof(*(a+1)));//7
printf("%d\n",sizeof(&a[0]+1));//8
printf("%d\n",sizeof(*(&a[0]+1)));//9
printf("%d\n",sizeof(*a));//10
printf("%d\n",sizeof(a[3]));//11
序号 解析

答案

1 数组名a单独放在sizeof中,计算的是整个数组的大小。 48 = 3 * 4 * sizeof(int)
2 a[0][0]表示数组第一行第一个元素。 4
3
  1. a[0]表示二维数组首元素地址,也就是第一个一维数组的数组名,a[0]就是单独存放在sizeof的数组名,计算的就是第一个一维数组的大小.
  2. a[0]可以写成*(a + 0),a是二维数组的第一个一维数组的地址,解引用就是第一个一维数组了.
4 * sizeof(int) = 16
4 a[0]表示第一个一维数组的数组名,并没有单独放在sizeof中,代表首元素的地址,+1,跳过一个元素,也就是&a[0][1]. 4 || 8
5 解引用后得到的是a[0][1] 4
6 a表示数组首元素的地址,+1就是第二个元素的地址,也就是第二个一维数组的地址, 4 || 8
7 解引用后就是第二个一维数组。 16
8 a[0]是第一行的数组名,&a[0]就是第一行的地址,+1后是第二行的地址,地址就是指针 4 || 8
9 解引用后就是第二行,计算的第二行的大小 16
10 *a就是第一行,计算的就是第一行的大小 16
11 a[3]是第四行的数组名,虽然没有第四行,但是sizeof并没有进行访问,所以并不是越界访问,根据类型仍然可以计算第四行的大小,4个整形变量。 16

总结 

数组名的意义:

  1.  sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。
  2.  & 数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表⽰⾸元素的地址。

相关推荐

  1. C语言----深入理解指针5

    2024-03-15 17:38:02       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-15 17:38:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-15 17:38:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-15 17:38:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-15 17:38:02       18 阅读

热门阅读

  1. Oracle Rac集群日常维护管理命令

    2024-03-15 17:38:02       16 阅读
  2. Rabbitmq---topics模型之动态路由

    2024-03-15 17:38:02       18 阅读
  3. IUV-5G全网仿真软件实训手册-手工整理

    2024-03-15 17:38:02       17 阅读
  4. 神经网络量化

    2024-03-15 17:38:02       17 阅读
  5. [Vue]插槽

    2024-03-15 17:38:02       19 阅读
  6. openssl生成免费证书

    2024-03-15 17:38:02       22 阅读