TvT——C语言进阶の刷题【1】:指针进阶

🎐 前情提要

✨本篇接上一篇C语言进阶の指针的知识,帮助大家进一步理解指针and数组的知识!

让我们开始吧!


👩🏻‍🏫作者: 初入编程的菜鸟哒哒
📚系列文章目录:

一、TvT——C语言初阶の数据存储
二、TvT——C语言进阶の指针
三、TvT——C语言进阶の字符函数和字符串函数
四、TvT——C语言进阶の自定义类型:结构体,枚举,联合



🥝一、sizeof与strlen的计算

在这里插入图片描述

🍭1.一些使用sizeof与strlen的基本认识

  • 先对数组名有个简要认知
  • 数组名是首元素地址,但是有两个例外
  1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
  2. &数组名 - 数组名表示整个数组,取出的是数组的地址

除上面两种特殊情况外,所有的数组名表示数组首元素地址

  • 再对sizeofstrlen有个简要认知:
  1. strlen: 是一个库函数,计算的是字符串的长度,并且只能针对字符串,遇‘\0’停止,计算的是\0之前的字符个数。
  2. sizeof: 是一个操作符(运算符),sizeof是用来计算变量所占内存空间的大小,任何类型都可以使用,只关注空间大小。

🍭2.sizeof计算整型数组

#include<stdio.h>
int main()
{
	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));
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:16 4/8 4 4/8 4 4/8 16 4/8 4/8 4/8

解析:

sizeof(a); :16 - 数组名a单独放在szieof内部 - 计算的是数组总大小 - 单位是字节 :4*4=16

sizeof(a + 0) : 4/8 - a表示的首元素的地址,a+0还是首元素地址,地址的大小就是(32位是4,64位是8)字节
sizeof(*a) : 4 - a表示的首元素的地址,*a就是对首元素地址的解引用,*a就是首元素a[0],sizeof(*a)就是4字节
sizeof(a + 1) : 4/8 - a表示的首元素的地址,a+1是第2个元素地址,地址的大小就是(32位是4,64位是8)字节
sizeof(a[1]) : 4 - a[1]是数组第二个元素的大小,4字节

sizeof(&a) : 4/8 - &a取出的是数组的地址,但是数组的地址也是地址,地址的大小就是(32位是4,64位是8)字节
sizeof(*&a) : 16 - 可以理解为 * 和&抵消效果,* &a相当于a,sizeof(a)是16字节
本质理解:
&a -> int( * )[4]
&a是数组的地址,它的类型是int(*)[4]数组指针,如果解引用,访问的就是4个int的数组,大小是16个字节

sizeof(&a + 1) :4/8 - &a是数组地址,&a+1虽然地址跳过整个数组,但还是地址,所以是(32位是4,>64位是8)字节,补充:&a到&a+1跳过了一个数组,a到a+1跳过了一个元素
sizeof(&a[0]) : 4/8 - &a[0]就是第一个元素的地址(32位是4,64位是8)字节
sizeof(&a[0] + 1) :4/8 - &a[0]就是第一个元素的地址,再+1就是第二个元素的地址(32位是4,64位是8)字节

🍭3.sizeof与strlen计算不同形式的字符数组

在这里插入图片描述

1️⃣ char arr[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };

在这里插入图片描述

🍐 sizeof()计算char arr[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };
#include<stdio.h>
int main()
{
	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));
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:6 4/8 1 1 4/8 4/8 4/8

解析:

sizeof(arr); :6 - arr作为数组名单独放在sizeof内部,计算的整个数组的大小,单位是字节,6字节

sizeof(arr + 0) : 4/8 - arr是首元素的地址,arr+0还是首元素的地址,地址的大小就是(32位是4,64位是8)字节
sizeof(*arr) : 1 - arr是首元素地址,*arr就是首元素,首元素是一个字符,大小是1个字节

sizeof(arr[1]) : 1 - arr[1]相当于第二个元素的大小,是一个字符,大小就是1字节

sizeof(&arr) : 4/8 - &arr虽然是数组的地址,但还是地址,地址的大小就是(32位是4,64位是8)字节
sizeof(&arr + 1) :4/8 - &arr+1是跳过整个数组后的地址,但还是地址,地址的大小就是(32位是4,64位是8)字节
sizeof(&arr[0] + 1) :4/8 - &arr[0]是第一个元素的地址,&arr[0]+1就是第二个元素的地址,地址的大小就是(32位是4,64位是8)字节

在这里插入图片描述

🍐 strlen()计算char arr[] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’ };
#include<stdio.h>
#include<string.h>
int main()
{
	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));
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:随机值 随机值 err err 随机值 随机值 随机值

解析:

strlen(arr); :随机值 - arr是首元素的地址,但是arr数组中没有\0,计算的时候就不知道什么时候停止

strlen(arr + 0) : 随机值 - arr是首元素的地址,arr+0还是首元素的地址
strlen(*arr)err - strlen需要的是一个地址,从这个地址开始向后找字符,直到\0,统计字符的个数。
但是*arr是数组的首元素,也就是’a’,这是传给strlen的就是’a’的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突

strlen(arr[1])err - 和上一个一样,内存访问冲突

strlen(&arr) : 随机值 - &arr是arr数组的地址,虽然类型和strlen的参数类型有所差异,但是传参过去后,还是从第一个字符的位置向后数字符,结果还是随机值
strlen(&arr + 1) :随机值 - &arr是数组的地址,+1跳过整个数组,但是arr数组中没有\0,计算的时候就不知道什么时候停止
strlen(&arr[0] + 1) :随机值 - 这里相当于从第二个字符的地址开始向后访问,又因为没有\0,所以还是随机值

在这里插入图片描述

2️⃣ char arr[] = “abcdef”;

在这里插入图片描述

🍐 sizeof()计算char arr[] = “abcdef”;
#include<stdio.h>
int main()
{
	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));
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:7 4/8 1 1 4/8 4/8 4/8

解析:

sizeof(arr); :7 - sizeof(arr)计算的数组的大小,单位是字节

sizeof(arr + 0) :4/8 - arr+0是首元素的地址,既然是地址,(32位是4,64位是8)字节
sizeof(*arr) : 1 - arr是首元素地址,首元素地址被解引用,*arr拿到的就是首元素,大小是1字节

sizeof(arr[1]) : 1 - arr[1]相当于第二个元素的大小,是一个字符,大小就是1字节

sizeof(&arr) : 4/8 - &arr虽然是数组的地址,但还是地址,地址的大小就是(32位是4,64位是8)字节
sizeof(&arr + 1) :4/8 - &arr+1是跳过整个数组后的地址,但还是地址,地址的大小就是(32位是4,64位是8)字节
sizeof(&arr[0] + 1) :4/8 - &arr[0]是第一个元素的地址,&arr[0]+1就是第二个元素的地址,地址的大小就是(32位是4,64位是8)字节

在这里插入图片描述

🍐 strlen()计算char arr[] = “abcdef”;
#include<stdio.h>
#include<string.h>
int main()
{
	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));
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:6 6 err err 6 随机值 5

解析:

strlen(arr); :6 - arr表示首元素地址,数到\0停下

strlen(arr + 0) : 6 - arr表示首元素地址,+0还是首元素地址,数到\0停下
strlen(*arr)err - strlen需要的是一个地址,从这个地址开始向后找字符,直到\0,统计字符的个数。
但是*arr是数组的首元素,也就是’a’,这是传给strlen的就是’a’的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突

strlen(arr[1])err - 和上一个一样,内存访问冲突

strlen(&arr) : 6 - &arr表示取出的整个数组地址,但是整个数组的地址还是这个数组的起始地址,还是从起始元素数到\0停止
strlen(&arr + 1) :随机值 - &arr表示取出的整个数组地址,+1表示跳过这整个数组,也跳过了原数组的\0,此时又找不到\0了,随机值
strlen(&arr[0] + 1) :5 - &arr[0]就是第一个元素的地址,+1就是第二个元素的地址,即从第二个元素开始数到\0停止

在这里插入图片描述

3️⃣ char* p = “abcdef”;

在这里插入图片描述

🍐 sizeof()计算char* p = “abcdef”;
#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));        // 4/8  p是一个指针变量,sizeof(p)计算的就是指针变量的大小,(32位是4,64位是8)字节
	printf("%d\n", sizeof(p + 1));    // 4/8  p是指针变量,是存放地址的,p+1也是地址,(32位是4,64位是8)字节
	printf("%d\n", sizeof(*p));       // 1    p是char*的指针,解引用访问1个字节,sizeof(*p)是1字节,可理解为p[0]-->*(p+0)-->*p
	printf("%d\n", sizeof(p[0]));     // 1    p[0]-->*(p+0)-->*p
	printf("%d\n", sizeof(&p));       // 4/8  &p也是地址,(32位是4,64位是8)字节,&p是二级指针
	printf("%d\n", sizeof(&p + 1));   // 4/8  &p是地址,+1后还是地址,(32位是4,64位是8)字节,&p + 1,是p的地址+1,在内存中跳过p变量后的地址
	printf("%d\n", sizeof(&p[0] + 1));// 4/8  p[0]就是a,&p[0]就是a的地址,&p[0]+1就是b的地址,(32位是4,64位是8)字节
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:4/8 4/8 1 1 4/8 4/8 4/8

解析:

sizeof(p); :4/8 - p是一个指针变量,sizeof§计算的就是指针变量的大小,(32位是4,64位是8)字节

sizeof(p + 0) : 4/8 - p是指针变量,是存放地址的,p+1也是地址,(32位是4,64位是8)字节
sizeof(*p) : 1 - p是char*的指针,解引用访问1个字节,sizeof(p)是1字节,可理解为p[0]–>(p+0)–>*p

sizeof(p[0]) : 1 - p[0]–>*(p+0)–>*p

sizeof(&p) : 4/8 &p也是地址,(32位是4,64位是8)字节,&p是二级指针
sizeof(&p + 1) :4/8 - &p是地址,+1后还是地址,(32位是4,64位是8)字节,&p + 1,是p的地址+1,在内存中跳过p变量后的地址
sizeof(&p[0] + 1) 4/8 - p[0]就是a,&p[0]就是a的地址,&p[0]+1就是b的地址,(32位是4,64位是8)字节

在这里插入图片描述

🍐 strlen()计算char* p = “abcdef”;
#include<stdio.h>
#include<string.h>
int main()
{
	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));
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:6 5 err err 随机值 随机值 5

解析:

strlen(p); :6 - p中存放的是’a’的地址,strlen§就是从’a’的位置向后求字符串的长度,长度是6

strlen(p + 0) : 5 - p+1是’b’的地址,从b的位置开始求字符串长度是5
strlen(*p)err - strlen需要的是一个地址,从这个地址开始向后找字符, 直到\0,统计字符的个数。
但是*p是数组的首元素,也就是’a’,这是传给strlen的就是’a’的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
strlen(p[0])err - 理由同上

strlen(&p) : 随机值 - p中存放的是’a’的地址,&p放的是p的地址,在p的地址中strlen找不到\0,所以随机值
strlen(&p + 1) :随机值 - 理由类似上部
strlen(&p[0] + 1) : 5 - p[0] -> *(p+0) -> *p ->‘a’ ,&p[0]就是首字符的地址,&p[0]+1就是第二个字符的地址从第2 字符的位置向后数字符串,长度是5

在这里插入图片描述

🍭4.sizeof计算二维数组

#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));           
	printf("%d\n", sizeof(a[0][0]));     
	printf("%d\n", sizeof(a[0]));       
	printf("%d\n", sizeof(a[0] + 1));  
	printf("%d\n", sizeof(*(a[0] + 1))); 
	printf("%d\n", sizeof(a + 1));      
	printf("%d\n", sizeof(*(a + 1)));   
	printf("%d\n", sizeof(&a[0] + 1));   
	printf("%d\n", sizeof(*(&a[0] + 1)));
	printf("%d\n", sizeof(*a));         
	printf("%d\n", sizeof(a[3]));       
	return 0;
}

请大家计算一下上面的结果都是什么呢?

✅答案是:48 4 16 4/8 4 4/8 16 4/8 16 16 16

解析:

sizeof(a) :48 - 数组名单独放置sizeof内部,计算的是整个数组的大小,344=48字节

sizeof(a[0][0]) :4 - a[0][0]表示第一行第一个元素的大小,类型是int,大小为4字节
sizeof(a[0]) : 16 - a[0]表示第一行的数组名,a[0]作为数组名单独放在sizeof内部,计算的是第一行数组的大小:16字节
但是*p是数组的首元素,也就是’a’,这是传给strlen的就是’a’的ascii码值97,strlen函数会把97作为起始地址,统计字符串,会形成内存访问冲突
sizeof(a[0] + 1) : 4/8 - a[0]作为第一行的数组名,没有&,没有单独放在sizeof内部,所以a[0]表示的就是首元素的地址,即a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,(32位是4,64位是8)字节

sizeof(*(a[0] + 1)) :4 - 既然解引用了,就是第一行第二个元素的大小4字节
sizeof(a + 1) :4/8 - a是二维数组的数组名,没有&,没有单独放在sizeof内部,a表示首元素的地址,即第一行的地址,a+1就是第二行地址。(32位是4,64位是8)字节,是类型为int()[4]的数组指针。
sizeof(*(a + 1)) : 16 -
(a+1)就是第二行,相当于第二行的数组名,(a+1)–>a[1],sizeof((a+1))计算的是第二行的大小,16字节
sizeof(&a[0] + 1) : 4/8 - a[0]是第一行的地址,&a[0]是第1行的地址,&a[0] + 1就是第二行的地址,(32位是4,64位是8)字节

sizeof(*(&a[0] + 1)) : 16 - *(&a[0] + 1)就相当于第二行,也就是a[1],sizeof(a[1]),大小是16字节
ssizeof(*a)) :16 - a二维数组的数组名,没有&,没有单独放在sizeof内部,a表示首元素的地址,*a就是二维数组的首元素,也就是第一行。a–>(a+0)–>a[0]
sizeof(a[3]) : 16 - 感觉a[3]是越界了,但是没关系,依旧把它当成是求某行的大小,16字节

在这里插入图片描述

总结

在这里插入图片描述

“莫愁千里路,自有到来风。”
我们顶峰相见!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值