首页 > 其他分享 >C语言--指针终章

C语言--指针终章

时间:2024-04-07 14:32:06浏览次数:18  
标签:arr 字节 -- C语言 地址 printf 终章 strlen sizeof

 

目录

 

1. sizeof和strlen的对⽐

1.1 sizeof

1.2 strlen

1.3 sizeof 和 strlen的对⽐

 2. 数组和指针的理解——题目理解

2.1.sizeof

代码1:

代码2:

代码3:

代码4:

代码5(二维数组):

2.2:strlen

代码1:

代码2: 

代码3:

代码4(模拟实现strlen的三种方式):


冰冻三尺,非一日之寒

1. sizeof和strlen的对⽐

1.1 sizeof

 sizeof 计算变量所占内存内存空间⼤⼩的,单位是 字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。

sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。 ⽐如:
#inculde <stdio.h>
int main()
{
 int a = 10;
 printf("%d\n", sizeof(a));
 printf("%d\n", sizeof a);
 printf("%d\n", sizeof(int));
 
 return 0;
}

1.2 strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:
size_t strlen ( const char * str );
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。 strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。
#include <stdio.h>
int main()
{
 char arr1[3] = {'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;
}

1.3 sizeof 和 strlen的对⽐

 2. 数组和指针的理解——题目理解

2.1.sizeof

代码1:

#include<stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };//数组有几个元素
	printf("%zd\n", sizeof(a));//16 -- sizeof(数组名)的场景
	printf("%zd\n", sizeof(a + 0));//a是首元素的地址-类型是int*,a+0还是首元素的地址,是地址大小就是4/8
	printf("%zd\n",sizeof(*a));//a是首元素的地址,*a就是首元素,大小就是4个字节
	//*a == a[0] == *(a+0)
	printf("%zd\n",sizeof(a + 1));//a是首元素的地址,类型是int*,a+1跳过1个整型,a+1就是第二个元素的地址,4/8
	printf("%zd\n",sizeof(a[1]));//a[1]就是第二个元素,大小4个字节
	printf("%zd\n",sizeof(&a));//&a是数组的地址,数组的地址也是地址,是地址大小就是4/8个字节
	printf("%zd\n",sizeof(*&a));//1.*& 互相抵消了,sizeof(*&a)= sizeof(a)-16
	//2. &a 是数组的地址,类型是int(*)[4],对数组指针解引用访问的是数组,计算的是数组的大小 -16
	printf("%zd\n",sizeof(&a + 1));//&a+1是跳过整个数组后的那个位置的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&a[0] + 1));//&a[0]+ 1 -- 数组第二个元素的地址,大小是4/8个字节
	printf("%zd\n",sizeof(&a[0]));//首元素的地址,大小4/8个字节
	return 0;
}

代码2:

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部,计算的是数组的大小,单位是字节--6
	
    printf("%d\n", sizeof(arr + 0));//arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节
	
    printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,大小就是1个字节
	//*arr --  arr[0] -- *(arr+0)等价
	
    printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小也是1个字节
	
    printf("%d\n", sizeof(&arr));//&arr是数组地址,数组的地址也是地址,大小是4/8
	//&arr -- char(*)[6]
	
    printf("%d\n", sizeof(&arr + 1));//&arr+1,跳过整个数组,指向了数组后边的空间,4/8个字节
	
    printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8字节

	return 0;
}

代码3:

include<stdio.h>
int main()
{
	char arr[] =  "abcdef" ;
	printf("%d\n", sizeof(arr));//arr是数组名,单独放在sizeof内部,计算的是数组中大小,是7个字节

	printf("%d\n", sizeof(arr + 0));//arr表示数组首元素的地址,srr+0还是首元素的地址,是地址就是4/8

	printf("%d\n", sizeof(&arr));//arr表示数组首元素的地址,*arr就是首元素。大小是1字节

	printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小是1个字节

	printf("%d\n", sizeof(&arr));//&arr是数组的地址,+1是跳过整个数组,还是地址,是地址就是4/8字节

	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]+1是第二个元素的地址,大小是4/8个字节

	return 0;
}

代码4:

#include<stdio.h>
int main()
{
	const char* p = "abcdef";
	printf("%d\n", sizeof(p));//p是指针变量,我们计算的是指针变量的大小,4/8个字节

	printf("%d\n", sizeof(p + 1));//p+1是b的地址,是地址大小就是4/8个字节

	printf("%d\n", sizeof(*p));//p的类型是const char*,*p就是char类型了,1个字节

	printf("%d\n", sizeof(p[0]));//1.p[0] --> *(p+0) --> *p --> 'a',大小是1字节
	//2.把常量字符串想象成数组,p可以理解为数组名,p[0]就是首元素

	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));//4/8 &p[0]-取出字符串首字符的地址,+1是第二个字符的地址,大小是4/8字节

	return 0;
}

代码5(二维数组):

#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//a是数组名,单独放在sizeof内部,计算的是数组打大小,单位是字节-48 =3*4*sizeof(int)

	printf("%d\n", sizeof(a[0][0]));//a[0][0] 是第一行第一个元素,大小4个字节

	printf("%d\n", sizeof(a[0]));//a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的中大小 16 个字节

	printf("%d\n", sizeof(a[0] + 1));//a[0]第一行的数组名,但是a[0]并没有单独放在sizeof内部,所以这里的数组名a[0]就是
	//数组首元素的地址,就是&a[0][0],+1后是a[0][1]的地址,大小是4/8个字节

	printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)表示第一行第二个元素,大小就是4(int类型)

	printf("%d\n", sizeof(a + 1));//a作为数组名并没有单独放在sizeof内部,a表示数组数组首元素的地址,是二维数组首元素的地址,也就是
	//第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址,a+1是数组指针,是地址大小就是4/8个字节

	printf("%d\n", sizeof(*(a + 1)));//1.a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小-16
	//2.*(a+1) == a[1],a[1]是第二行的数组名,sizeof(*(a+1))就相当于sizeof(a[1]),意思是把第二行的数组名单独放在
	//sizeof内部,计算的是第二行的大小

	printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]取出的是数组的地址,就是第一行的地址
	//&a[0]+1 就是第二行的地址,是地址大小就是4/8个字节

	printf("%d\n", sizeof(*(&a[0] + 1)));//*(a[0] + 1)意思是对第二行的地址解引用,访问的就是第二行,大小就是16字节 
	
	printf("%d\n", sizeof(*a));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
	//第一行的地址,*a就是第一行,计算的是第一行的大小,16字节
	//*a == *(a+0) ==a[0]

	printf("%d\n", sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型的推断就能算出长度
	//a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16字节

	return 0;
}

2.2:strlen

代码1:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//arr是首元素的地址,数组中没有\0,就会导致越界访问结果是随机的
	
	printf("%d\n", strlen(arr + 0));//arr+0是首元素的地址,数组中没有\0,就会导致越界访问是随机的
	
	printf("%d\n", strlen(*arr));//arr是首元素的地址,*arr是首元素,就是‘a’,‘a'的ascii码值是97
	//就相当于打97作为地址传递给了strlen,strlen得到的就是野指针,代码是有问题
	printf("%d\n", strlen(arr[1]));//arr[1]--'b'--98.传给strlen函数也是错误的

	printf("%d\n", strlen(&arr));//&arr是数组的地址,起始位置是数组的第一个元素的位置,随机值 x

	printf("%d\n", strlen(&arr + 1));//随机值x-6

	printf("%d\n", strlen(&arr[1] + 1));//第2个元素开始向后统计的,得到的也是随机值 x-1
	return 0;
}

代码2: 

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部,计算的是数组的大小,单位是字节--6
	printf("%d\n", sizeof(arr + 0));//arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,大小就是1个字节
	//*arr --  arr[0] -- *(arr+0)等价
	printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小也是1个字节
	printf("%d\n", sizeof(&arr));//&arr是数组地址,数组的地址也是地址,大小是4/8
	//&arr -- char(*)[6]
	printf("%d\n", sizeof(&arr + 1));//&arr+1,跳过整个数组,指向了数组后边的空间,4/8个字节
	printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8字节

	return 0;
}

代码3:

#include<stdio.h>
#include<string.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));//6

	printf("%d\n", strlen(p + 1));//5
	
	pritnf("%d\n", strlen(*p));//*p就是‘a'-97,err

	printf("%d\n", strlen(p[0]));//p[0]-->*(p+0)-->*p //err

	printf("%d\n", strlen(&p));//&p是指针变量p的地址,和字符串“abcdef”关系不大
	//从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以答案是随机值

	printf("%d\n", strlen(&p + 1));//随机值

	printf("%d\n", strlen(&p[0] + 1));//5
	return 0;
}

代码4(模拟实现strlen的三种方式):

#include<stdio.h>
#include<string.h>
#include<assert.h>

//计算器方式
int my_strlen1(char* str)
{
	int count = 0;
	assert(str);
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

//不创建临时变量记数器(递归)
int my_strlen2(const char* str)
{
	assert(str);
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen2(str + 1);
}

//指针-指针的方式
int my_strlen3(char* str)
{
	assert(str);
	char* p = str;
	while (*p != '\0')
		p++;
	return p - str;
}

int main()
{
	char *a = "abcdef";
	int s = my_strlen1(a);
	printf("%d\n", s);
	return 0;
}

标签:arr,字节,--,C语言,地址,printf,终章,strlen,sizeof
From: https://blog.csdn.net/pzn2506/article/details/137429027

相关文章

  • app闪退的原因--一起学习吧之测试
    一、闪退原因内存或存储空间不足:当应用程序使用过多的内存或存储空间时,可能会导致应用程序崩溃。这通常发生在设备上运行内存或存储空间不足的情况下。线程问题:如果应用程序中的线程没有正确管理或者存在死锁情况,可能导致应用程序崩溃。无效的输入或数据错误:当应用程序接收到......
  • 网页崩溃的原因是什么--一起学习吧之测试
    一、网页崩溃的原因代码错误:网页的前端代码(如HTML、CSS和JavaScript)中可能存在错误,例如语法错误、逻辑错误或代码冲突。这些错误可能导致网页无法正确渲染或执行,进而导致崩溃。内存问题:网页使用的内存超过了浏览器或设备的限制。内存泄漏是常见的问题,当网页长时间运行时,如果不......
  • 电脑桌面上表格不见了怎么找回?这5个方法不要错过
    在日常的办公和学习中,电脑桌面上的各种文件、文件夹和表格等无疑是我们较为频繁使用的资源。然而,有时我们可能会因为一些操作失误或者电脑问题,突然发现桌面上的某个表格文件神秘失踪了。面对这种情况,很多人可能会感到焦虑和不知所措。但别担心,本文将为你提供几种方法,希望能帮助......
  • 全量知识系统 程序详细设计之“命名法” “正文”的“ 前言“ 之1 “前提”篇
    前言本期(“命名法”系列篇)的主题(“命名法”)将给出全知系统的命名规则,计划将从正文的第三部分起。作为在进入本期“命名法”系列篇主题前的准备,本“前言”中规划了两部分,它们的主题词是“语言游戏”:“序言”部:全知系统中语言游戏 的三种玩法(“三种玩法”)“导言”部: ......
  • 全量知识系统 程序详细设计 “三次演算” 再探(Q&A)之2 (百度搜索)
    说明:以下关于全知系统中程序详细设计的沟通是基于今天正在完成中的全量知识系统程序详细设计之“命名法”“正文”的"前言"之1“前提”篇中提出的所有程序要求的基础上的。(这些相同问题的同时沟通 )Q1.这些规则在程序被设计为λ表达式的三个转换规则,分别适用于三条线......
  • 承包学校洗衣房如何运营成功
    近年来,校园洗衣模式的升级版——共享智能柜+校园洗衣工厂,受到社会上越来越多人的关注。除了校方和学生外,很多有学校资源的创业者、投资商,也都对校园智能洗衣格外感兴趣,有一部分已经在当地建设了校园智能洗衣工厂,着手推进项目了。然而,由于先前没有做过做过校园洗衣生意,很多......
  • nginx怎么设置拦截请求
    Nginx设置拦截请求可以通过多种方式实现,具体取决于您想要拦截的请求类型、条件以及拦截后的处理方式。以下是几种常见的拦截请求场景及其配置方法:1.基于IP地址的拦截可以使用 allow 和 deny 指令来允许或拒绝特定IP地址或IP段的访问。通常放在 http, server,或 l......
  • AI绘画教程 浴室马桶都卷到这个程度啦?
    用AI绘画制作电商效果图,是目前AI设计功能中比较普遍的一种用法。相较于传统设计来说,AI绘画能够直接把产品的相关视觉效果拉到极致,包括产品的展示图、产品的实际使用图等等。通过这种方法能够极大地增强产品的吸引力,今天我们就一起试试看,看看如果我们用StartAI制作一个高级马桶......
  • Unity WebGL火狐浏览器配置
    特此声明:此配置容易内存溢出,只适合小型Webgl运行,推荐使用本地服务器打开WebGL火狐浏览器下载地址:https://www.firefox.com.cn/1.打开火狐浏览器输入:about:config2.将这几项,设置对应属性ebgl.force-enabledtruewebgl.disabled......
  • 镜头产品分类-取像镜头1
    目录LensDimensionImageCircleofLensEFLandFOVFNO​RelativeIllumination针对取像镜头重点说明如下:LensDimension1.TTL:光学总长2.BFL:后焦长度3.M12:螺牙锁附承靠的尺寸4.Ø14:镜头最大外径 ImageCircleofLens1.单纯就以镜头做为说明,可看......