sizeof和strlen的区别、sizeof(a)与sizeof(a+0)区别在哪里?sizeof(*a)、sizeof(a+1)、sizeof(a[1])...... | 笔试题分析| 超全

在经历的数组指针指针数组数组指针...的学习过后,我们真的很难很清晰的去理解,它们之间的关系究竟是什么,下面小编就以一道笔试题来为大家清晰地讲解一下sizeofstrlen中计算情景不同的类型,以及使用方式。

一、必备知识点

我们首先需要掌握sizeofstrlen不同使用方式:

(1)sizeof()的使用方式

sizeof其实仅仅只是一个操作符,我们要注意它并不是一个函数,他就类似与常见的+、=、-......的操作符,并且sizeof是一个单目操作符。sizeof实际上是获取了数据在内存中所占用的存储空间,以字节为单位来计数。

sizeof()用于数据类型

我们在初学C语言时,就已经知道了sizeof可以计算各种数据类型的所占的存储空间。例如,回忆一下以下代码:

#include 
int main()
{
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof(char));
	printf("%d\n", sizeof(short));
	printf("%d\n", sizeof(long));
	printf("%d\n", sizeof(long long));
	printf("%d\n", sizeof(double));
	printf("%d\n", sizeof(float));
	printf("%d\n", sizeof(long double));

	return 0;
}

运行出来的结果为(不同的计算器运行的结果部分不同):

4
1
2
4
8
8
4
8

sizeof()用于变量

sizeof用于变量,计算整个数组的大小,单位是字节。

我们可以看一下下面的例子:

#include 
int main()
{
	int a = 5;
	int b = 10;
	int arr[] = { 1,2,3,4 };

    printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(b));
	printf("%d\n", sizeof(arr));
	
	return 0;
}

运行的结果为:

4
4
16 

(2)strlen()的使用方式

strlen()是一个函数,是字符串中字符的个数。 sizeof () 可以用于任何类型的数据,而 strlen () 只能用于以空字符 '\0' 结尾的字符串。

size_t strlen ( const char * str ) ;

strlen函数的头文件:

#include 

这里我们注意需要向strlen中传入一个字符串地址,通过这个地址strlen函数计算其字符的个数。例如,以下代码:

int a = 0;
pritnf("%d\n", strlen(a));

这个代码,它明显是错误的,因为他不满足一下两点:

  • strlen是一个计算字符串字符的个数。
  • strlen需要的被传参进去一个字符串地址

而正确的使用方式:

#include 
#include 
int main()
{
	char arr[] = {'a','b','c','d','e','f'};
	char arr1[] = { 'a','b','c','d','e','f','\0'};

	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(&arr1));

	return 0;
}

要注意strlen计算的是字符串‘\0’以前的字符个数,而在上面的代码中arr数组,并没有‘\0’,所以并不知道‘\0’在内存的什么地方。

 运行的结果为:

随机值

6

(3)数组名的含义

除了上面我们需要掌握的之外,更重要的我们要知道,数组名的含义;我们在学习过程中,似乎经常遇到“首元素地址”,那么数组名究竟是如何理解的呢?我为大家整理了一下总结:

数组名首元素地址,但是有两个例外:

  • sizeof(数组名),计算的是整个数组的大小;
  • &数组名,取的是整个数组的地址。

二、sizeof()和strlen()笔试题

(一)一维数组:

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

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

printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

sizeof用于变量,计算整个数组的大小,单位是字节。

 那我们现在依次来分析:

  • sizeof(a)

int a[] = {1,2,3,4};//4个元素,每个元素是int类型(4个字节)
printf("%d\n",sizeof(a));//16
                         //数组名a单独放在sizeof内部,数组名表示整个数组,计算的是整个数组的大小
                         //单位是字节,16字节

a[ ] 这个数组整个是占16个字节,我们看这个sizeof(a) ,而这里sizeof(数组名)表示的是整个数组,其计算的是整个数组的大小,单位是字节。

运行结果:

16

  • sizeof(a+0)

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

 这里的sizeof(a+0)中a并没有单独放到sizeof内部,也没有取地址,所以数组名表示首元素地址。sizeof(a+0)中a+0还是首元素地址,地址的大小是4/8个字节。

  • sizeof(*a)

int a[] = {1,2,3,4};
printf("%d\n",sizeof(*a));

a并没有单独放到sizeof内部,也没有取地址,所以数组名表示首元素地址。sizeof(*a)中*a就是指向首元素地址解引用,所以就是首元素,大小是4个字节。也可以理解为:

*a == *(a+0)== a [ 0 ]

所以运行结果:

  • sizeof(a+1)

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a+1));

 这里的sizeof(a+1)中a并没有单独放到sizeof内部,也没有取地址,所以数组名表示第二个元素嗯的地址,是地址,地址的大小是4/8个字节。

a + 1 ==  &a[ 1 ]

所以运行结果:

4 、8

  • sizeof(a[1])

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a[1]));

a[1]就是数组的第二个元素,这里计算的就是第二个元素的大小,单位是字节,所以是4字节。

所以运行结果:

  • sizeof(&a)

int a[] = {1,2,3,4};
printf("%d\n",sizeof(&a));

 &a是取出数组的地址,但是数组的地址也是地址,是地址就是4/8个地址。

数组的地址数组首元素的地址 的本质区别:

类型的区别,并非大小的区别。

所以运行结果:

4、8

  • sizeof(*&a)

int a[] = {1,2,3,4};
printf("%d\n",sizeof(*&a));

 sizeof(*&a)这个是数组指针类型,对数组指针类型解引用,访问的数组的大小,所以是4个字节。

sizeof(*&a)---  sizeof(a)

  • sizeof(&a+1)

int a[] = {1,2,3,4};
printf("%d\n",sizeof(&a+1));

sizeof(&a+1)中&a是地址,&a+1仍然是地址,是地址就是4/8字节。

所以运行结果:

4、8

  • sizeof(&a[0])

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

 sizeof(&a[0])中&a[0]是首元素的地址,计算的是地址的大小4/8个字节。

所以运行结果:

4、8

  • sizeof(&a[0]+1)

int a[] = {1,2,3,4};
printf("%d\n",sizeof(&a[0]+1));

 sizeof(&a[0]+1)中&a[0]是首元素地址,所以 sizeof(&a[0]+1) 是第二个元素的地址,大小为4/8个字节。

第二个元素的地址表达方式:

  • &a[ 1 ]
  • &a[ 0 ] + 1
  • a+1

(二)字符数组

1 . char arr[]={'a','b','c','d','e','f'}

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
  • sizeof(arr)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));

数组名arr单独放在sizeof内部,计算的是整个数组大小,单位是字节,所以大小是6个字节。

  • sizeof(arr+0)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr+0));

数组名arr没有单独放在sizeof内部,所以arr是首元素地址,arr+1是第二个元素的地址,是地址就是4/8个字节。

指针类型的大小和类型无关,不管什么类型的之争变量,大小都是4/8个字节。指针变量是用来存放地址的,地址存放需要多大的空间,指针变量的大小就是几个字节。

32位环境下,地址是32个二进制位,需要4个字节,所以指针变量的大小就是4个字节。

64位环境下,地址是64个二进制位,需要8个字节,所以指针变量的大小就是8个字节。

  • sizeof(*arr)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(*arr));

 sizeof(*arr)中*arr中arr没有单独放在sizeof内部,也没有取地址,所以这个arr是首元素的地址,所以*arr是首元素。大小为1个字节。

  • sizeof(arr[1])

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr[1]));

 sizeof(arr[1])就是第二个元素,也就是1个字节。

  • sizeof(&arr)

char arr[] = {'a','b','c','d','e','f'}
printf("%d\n", sizeof(&arr));

 sizeof(&arr)中&arr是数组的地址,就是4/8个字节。

  • sizeof(&arr+1)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(&arr+1));

  sizeof(&arr+1)中&arr+1,是跳过数组后的地址,是地址就是4/8个字节。

  • sizeof(&arr[0]+1)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(&arr[0]+1));

  sizeof(&arr[0]+1)中&arr[0]+1就是第二个元素的地址,是地址就是4/8字节。

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));

strlen求字符串长度,统计的是在字符串中 ' \0 '之前出现字符的个数。 

  • strlen(arr)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));

注意这个arr中并没有 ' \0 ',所以并不知道什么时候会遇见 ' \0 '。arr是首元素地址,所以大小是随机值。

  • strlen(arr+0)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr+0));

注意这个arr+0中arr是首元素地址,所以并不知道什么时候会遇见 ' \0 '。所以大小是随机值。

  • strlen(*arr)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(*arr));

arr是首元素地址,*arr就是首元素,就是字符 ' a ',在ASCII码值中,字符' a '就是97。而在strlen的角度,认为传参进去的 ' a '97就是地址,直接进行访问,就是非法访问,所以会报错。

 size_t strlen ( const char * str ) ;

所以strlen需要传入一个地址

  • strlen(arr[1])

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr[1]));

 同理上面的,arr[ 1 ]就是字符' b '98,在strlen的角度,认为传参进去的 ' a '97就是地址,直接进行访问,就是非法访问,所以会报错。

  • strlen(&arr)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(&arr));

 strlen(&arr)中&arr是arr的地址,仍然因为这个数组中并没有' \0 ',所以是随机值。

  • strlen(&arr+1)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(&arr+1));

 与上面的同理,&arr+1也是同样的随机值。

  • strlen(&arr[0]+1)

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(&arr[0]+1));

同理这个我们,&arr[ 0 ]+1也是随机值。

2 . char arr[] = "abcdef"

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

我们要注意:字符串中默认最后一个是有 ' \0 '的。 

  • sizeof(arr)

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));

 arr单独放在sizeof中,表示的整个数组的大小,加上' \0 '其实就是7个字节。

  • sizeof(arr+0)

char arr[] = "abcdef";
printf("%d\n", sizeof(arr+0));

数组名arr没有单独放在sizeof内部,所以arr是首元素地址,arr+1是第二个元素的地址,是地址就是4/8个字节。

  • sizeof(*arr)

char arr[] = "abcdef";
printf("%d\n", sizeof(*arr));

 arr没有单独使用在sizeof中,所以arr是首元素地址,所以*arr是首元素,所以大小是1个字节。

  • sizeof(arr[1])

char arr[] = "abcdef";
printf("%d\n", sizeof(arr[1]));

第二个元素,大小是1个字节。

  • sizeof(&arr)

char arr[] = "abcdef";
printf("%d\n", sizeof(&arr));

&arr取出数组的地址,数组的地址也是地址,是地址就是4/8个字节。

  • sizeof(&arr+1)

char arr[] = "abcdef";
printf("%d\n", sizeof(&arr+1));

 &arr+1也是地址,是地址就是4/8个字节。

  • sizeof(&arr[0]+1)

char arr[] = "abcdef";
printf("%d\n", sizeof(&arr[0]+1));

 第二个元素的地址,是地址就是4/8个字节。

char arr[] = "abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
  • strlen(arr)

char arr[] = "abcdef";
printf("%d\n", strlen(arr));

arr没有取地址,也没有单独放在sizeof内部,所以数组名arr是首元素的地址,所以加上字符串最后的' \0 ',所以大小是6。

  • strlen(arr+0)

char arr[] = "abcdef";
printf("%d\n", strlen(arr+0));

 rr没有取地址,也没有单独放在sizeof内部,所以数组名arr是首元素的地址,arr+0仍然是加上字符串最后的' \0 ',所以大小是6。

  • strlen(*arr)

char arr[] = "abcdef";
printf("%d\n", strlen(*arr));

 arr是首元素地址,*arr是首元素,因为strlen需要传入一个地址,所以会报错。

  • strlen(arr[1])

char arr[] = "abcdef";
printf("%d\n", strlen(arr[1]));

arr[ 1 ]是第二个元素,所以会报错。

  • strlen(&arr)

char arr[] = "abcdef";
printf("%d\n", strlen(&arr));

 &arr地址,取出arr的地址,从从前往后统计知道' \0 ',所以是6个字节。

  • strlen(&arr+1)

char arr[] = "abcdef";
printf("%d\n", strlen(&arr+1));

取arr的地址,跳过arr的地址,我们并不知道什么时候会遇到' \0 ',所以是随机值。

  • strlen(&arr[0]+1)

char arr[] = "abcdef";
printf("%d\n", strlen(&arr[0]+1));

arr[ 0 ]+1的地址,就是第二个元素地址,所以大小是5个字符。

3 . char *p = "abcdef"

char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));

 这里注意我们不是单纯地将"abcdef"放到*p中去的,一定有一块常量字符串​​​​​​被存储起来,假设这块的起始地址是0x0012ff40,而还有一块内存p存储着0x0012ff40,其指向"abcdef"。

  • sizeof(p)

char *p = "abcdef";
printf("%d\n", sizeof(p));

计算的是指针变量的大小,相当于地址,就是4/8。 

  • sizeof(p+1)

char *p = "abcdef";
printf("%d\n", sizeof(p+1));

假设p是0x0012ff40,所以p+1,指向0x0012ff41,p+1仍然是一个地址,是地址就是4/8个字节。

  • sizeof(*p)

char *p = "abcdef";
printf("%d\n", sizeof(*p));

 *p是char*的指针,解引用访问一个字节。

*p == ' a '

  • sizeof(p[0])

char *p = "abcdef";
printf("%d\n", sizeof(p[0]));

仍然是字符' a ' ,所以是1个字节。

p[0] == *(p+0)

  • sizeof(&p)

char *p = "abcdef";
printf("%d\n", sizeof(&p));

 这里就是相当于二级指针char**,是地址就是4/8个字节。

  • sizeof(&p+1)

char *p = "abcdef";
printf("%d\n", sizeof(&p+1));

取地址+1,仍然是地址,是地址就是4/8个字节。

  • sizeof(&p[0]+1)

char *p = "abcdef";
printf("%d\n", sizeof(&p[0]+1));

 &p[ 0 ]就是第一个地址,&p[ 0 ]+1就是第二个元素的地址,所以就是5个字节。

char *p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1);
  • strlen(p)

char *p = "abcdef";
printf("%d\n", strlen(p));

默认字符串有' \0 ',所以是6个字节。 

  • strlen(p+1)

char *p = "abcdef";
printf("%d\n", strlen(p+1));

 跳过一个字节,所以是5个字节。

  • strlen(*p)

char *p = "abcdef";
printf("%d\n", strlen(*p));

*p指向的是一个字符' a ' ,与前面的相同,strlen需要传入一个地址,所以会报错。

  • strlen(p[0])

char *p = "abcdef";
printf("%d\n", strlen(p[0]));

p[ 0 ]相当于就是第一个字符' \0 ',同样也会报错。

  • strlen(&p)

char *p = "abcdef";
printf("%d\n", strlen(&p));

&p取的是地址,此时并不知道什么时候会出现' \0 ',所以是一个随机值。

  • strlen(&p+1)

char *p = "abcdef";
printf("%d\n", strlen(&p+1));

与上面的同理,此时并不知道什么时候会出现' \0 ',所以是随机值。

  • strlen(&p[0]+1) 

char *p = "abcdef";
printf("%d\n", strlen(&p[0]+1);

&p[ 0 ] +1是第二个字符' b ',所以从字符' b '开始是5字符。

你可能感兴趣的:(初识C语言(一),C语言经典题目,算法,数据结构,c语言)