首页 > 其他分享 >深入了解指针(8)

深入了解指针(8)

时间:2024-08-14 23:27:20浏览次数:11  
标签:arr zd int 了解 深入 printf sizeof strlen 指针

文章目录

1. sizeof和strlen的对⽐

1.1 sizeof

在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。
sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。

 int main()
{
	int a = 0;
	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 );
int main()
{
char arr1[] = { ‘a’,‘gh’,‘s’,‘f’};
char arr2[] = “abcefgh”;
printf(“%d\n”, strlen(arr1));
printf(“%d\n”, strlen (arr2));//strlen 需要包含#include

printf("%d\n", sizeof(arr1));
printf("%d\n", sizeof(arr2));

return 0;
}
在这里插入图片描述

1.3 sizeof和strlen的对⽐

sizeof:

  1. sizeof是操作符
  2. sizeof计算操作数所占内存的⼤⼩,单位是字节
  3. 不关注内存中存放什么数据

strlen:
4. strlen是库函数,使⽤需要包含头⽂件 string.h
5. srtlen是求字符串⻓度的,统计的是 \0 之前字符的个数
6. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界

2. 数组和指针笔试题分析

接下来的代码环境都是在32位下

2.1一维数组

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	    //数组名是数组首元素的地址
	//但是有两个例外:
	//1. sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
	//2. &数组名,数组名表示整个数组,取出的是整个数组的地址
  int a[] = { 1,2,3,4 };
  printf("%zd\n", sizeof(a));// 16  a代表数组名,数组中4个整数大小为4*4=16  
  printf("%zd\n", sizeof(a + 0));// 4/8  首元素地址 ,地址在32位下为8,64位下为4
  printf("%zd\n", sizeof(*a)); // 4 首元素大小
  printf("%zd\n", sizeof(a + 1));// 4/8 首元素地址+1
  printf("%zd\n", sizeof(a[1])); // 4   代表a[1]元素大小  
  printf("%zd\n", sizeof(&a));// 4/8  整个数组的地址还是地址
  printf("%zd\n", sizeof(*&a));//  16 整个数组大小
  printf("%zd\n", sizeof(&a + 1));// 4/8 (&a+1)代表跳过数组的下一个地址,还是地址所以还是4/8
  printf("%zd\n", sizeof(&a[0]));// 4/8 首元素地址
  printf("%zd\n", sizeof(&a[0] + 1));// 4/8 首元素地址+1(下一个地址)
	return 0;
}

%zd修饰size_t类型比%d更准确
在这里插入图片描述

2.2 字符数组

代码1:
//字符数组

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", sizeof(arr));// 6  数组的大小6个字符大小为6
	printf("%zd\n", sizeof(arr + 0)); // 4/8  首地址大小
	printf("%zd\n", sizeof(*arr));// 1  arr是首元素的地址,*arr 就是首元素
	printf("%zd\n", sizeof(arr[1]));// 1 arr[1]这个元素大小
	printf("%zd\n", sizeof(&arr));// 4/8 数组地址
	printf("%zd\n", sizeof(&arr + 1));// 4/8 (&a+1)代表跳过数组的下一个地址,还是地址所以还是4/8
	printf("%zd\n", sizeof(&arr[0] + 1));//  4/8 &arr[0]+1是第二个元素的地址,是地址大小4/8个字节
	return 0;
}

在这里插入图片描述
代码2:

char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", strlen(arr));// 随机值 没有标注\0
printf("%zd\n\n\n", strlen(arr + 0));// 随机值 首元素地址向后找到、0
//printf("%zd\n", strlen(*arr));// 报错 arr[1] 指的是'a' 在指的是97 streln会把97当作地址 向后统计字符串长度 97作为地址的空间,不一定属于当前程序
//printf("%zd\n", strlen(arr[1]));// 报错 'b'-98 也是非法访问
printf("%zd\n", strlen(&arr));// 随机值 &arr数组地址传给strlen向找\0
printf("%zd\n", strlen(&arr + 1));// 随机值  没有\0
printf("%zd\n", strlen(&arr[0] + 1)); // 随机值 

return 0;

在这里插入图片描述

在这里插入图片描述
代码 3:

char arr[] = "abcdef";
printf("%zd\n", sizeof(arr));// 7 字符串大小\0也算
printf("%zd\n", sizeof(arr + 0));// 4/8 首元素地址
printf("%zd\n", sizeof(*arr));// 1 首元素大小
printf("%zd\n", sizeof(arr[1]));// 1 'a'字符大小
printf("%zd\n", sizeof(&arr));// 4/8 
printf("%zd\n", sizeof(&arr + 1));// 4/8
printf("%zd\n", sizeof(&arr[0] + 1));// 4/8

代码4:

char arr[] = "abcdef";
printf("%zd\n", strlen(arr));// 6  \0之前的字符个数
printf("%zd\n", strlen(arr + 0));// 6 首地址地址向后找\0
printf("%zd\n", strlen(*arr));//  报错   'a'-97
printf("%zd\n", strlen(arr[1]));//报错 ’b'-98 
printf("%zd\n", strlen(&arr));//6 首地址向后找到\0
printf("%zd\n", strlen(&arr + 1));// 随机值 
printf("%zd\n", strlen(&arr[0] + 1));//5 

代码5:

char* p = "abcdef";
printf("%zd\n", sizeof(p));// 4/8  p是指针变量 计算的是指针变量的大小
printf("%zd\n", sizeof(p + 1));// 4/8 p+1是'b'的地址
printf("%zd\n", sizeof(*p)); // 1 *p-'a'
printf("%zd\n", sizeof(p[0]));// 1 把p[]当数组p[0]-'a'
printf("%zd\n", sizeof(&p));// 4/8 整个字符串地址
printf("%zd\n", sizeof(&p + 1));// 4/8
printf("%zd\n", sizeof(&p[0] + 1));// 4 / 8

在这里插入图片描述
代码6:

char* p = "abcdef";
printf("%zd\n", strlen(p));//6
printf("%zd\n", strlen(p + 1));//5 
printf("%zd\n", strlen(*p));//报错 *p-'a'
printf("%zd\n", strlen(p[0]));//报错 'a'
printf("%zd\n", strlen(&p));//随机值
printf("%zd\n", strlen(&p + 1));//随机值
printf("%zd\n", strlen(&p[0] + 1));//5

2.3 ⼆维数组

int a[3][4] = { 0 };
printf("%zd\n", sizeof(a));//48 整个数组
printf("%zd\n", sizeof(a[0][0]));//4
printf("%zd\n", sizeof(a[0]));//16   a[0][]一维数组,a[0]是第一行的数组名,现在单独放在sizeof内部,计算的是第一行的大小
printf("%zd\n", sizeof(a[0] + 1));// 4/8  地址
printf("%zd\n", sizeof(*(a[0] + 1)));//4  *(a[0] + 1) 是第一行第二个元素,4个字节
printf("%zd\n", sizeof(a + 1));// 4/8  首地址+1
printf("%zd\n", sizeof(*(a + 1)));// 16 a[1][]
printf("%zd\n", sizeof(&a[0] + 1));//4/8  &a[0]+1就是第二行的地址,是地址就是4/8个字节
printf("%zd\n", sizeof(*(&a[0] + 1)));//16
printf("%zd\n", sizeof(*a));//16
printf("%zd\n", sizeof(a[3]));//16 不存在越界,因为不会真实的访问内存,仅仅是通过类型推导就可以知道长度的

在这里插入图片描述

3. 指针运算笔试题分析

代码1:

    int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%zd,%zd", *(a + 1), *(ptr - 1));
	// *(a+1)--指向 数组第一2个元素 2
//(ptr-1)--强制类型转换int* -1 到了数组最后一个元素地址 ,所以*(ptr-1)=5

在这里插入图片描述
代码2:

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p = (struct Test*)0x100000;
int main() 
{   //0x16进制
	printf("%p\n", p + 0x1);//结构体20个字节 0x100014
	printf("%p\n", (unsigned long)p + 0x1);//unsigned long一个字节  0x100001
	printf("%p\n", (unsigned int*)p + 0x1);//0x100004
	return 0;
}

代码3:

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);//1 注意,表达式的操作使用  (0,1)就是1
	return 0;
}

代码4:

在这里插入图片描述

//假设环境是x86环境,程序输出的结果是啥?

int a[5][5];
int(*p)[4];
p = a;
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//%p内存中的补码以16进制的形式打印 -4的 源码 10000000 00000000 00000000 00000100
                                                                                             //     补码 11111111 11111111 11111111 11111100
return 0;                                                                                    //           F  F      F  F     F   F    F  C

代码5:

int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//  10 (&aa+1)第三行首地址 int*类型*(ptr1-1)- 5,
                                          //  5   第二行首地址 
return 0;            

代码6:

char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);// "at"  pa++ -*pa到了"at"
return 0;

代码7:
在这里插入图片描述

char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;     //注意++cpp会运算效果保留
printf("%s\n", **++cpp);//"POINT" **++cpp  -c+2-"POINT"
printf("%s\n", *-- * ++cpp + 3);//"ER" 再++cpp 到了c+1 - "NEW" 再(--)就到了 "ENTER" 再首元素+3 到了"ER"
printf("%s\n", *cpp[-2] + 3);//"ST" 接上面 使用*cpp[-2] 就到了c+3 - "FIRST" 再首元素+3 到了"ST"
printf("%s\n", cpp[-1][-1] + 1);//"EW"  第三个的运算没有产生后续影响 所以cpp[-1][-1]到了"NEW" 再首元素+1就是"EW"
return 0;

指针系列就结束了,后面会出一篇将这些指针系列整理起来形成一篇大型的总篇章(⑅•͈ᴗ•͈).:*♡

标签:arr,zd,int,了解,深入,printf,sizeof,strlen,指针
From: https://blog.csdn.net/2401_85487314/article/details/141175517

相关文章

  • 从什么方面了解流程表单设计器开发的优势?
    众所周知,实现高效办公可以借助低代码技术平台的力量。因为这是目前广泛用于通信业、医疗、高校、制造业等很多行业领域中的理想软件平台。凭借诸多优势特点,在推动企业做好数据管理的过程中事半功倍,作用显著。本文将从以下几个方面为大家介绍低代码技术平台、流程表单设计器开发的......
  • 【人工智能】深入理解自监督学习中的表征学习与对比学习
     我的主页:2的n次方_1.自监督学习1.1自监督学习的概念自监督学习是一种无需大规模标注数据的学习方法,通过构造代理任务,模型可以从数据本身获取监督信号,从而学习有用的特征表征。1.2自监督学习的背景与重要性在当今大数据时代,数据标注往往成为机器学习应用中的一大......
  • 深入理解 ThreadLocal:机制、原理与实践
    引言ThreadLocal是Java中一个非常重要的工具,广泛用于解决多线程环境下变量共享的问题。然而,ThreadLocal的使用也可能带来一些隐患,尤其是在结合线程池的场景中,可能导致数据混乱。本文将深入探讨ThreadLocal的工作机制及其可能带来的问题,并给出相应的解决方案。一、Thr......
  • 驾驭时间的力量:深入探索时间序列分析的艺术
    标题:驾驭时间的力量:深入探索时间序列分析的艺术时间序列分析是一种统计技术,用于分析按时间顺序排列的数据点,以识别模式、趋势和周期性。它广泛应用于金融、经济、气象学、社会科学等领域。本文将详细介绍时间序列分析的基本概念、方法和实际应用,并通过Python代码示例展示其......
  • html基础入门(css,js初步了解)
    大家好我是猫咪!!!<!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <title>Title</title><!--  引入一个外部的css文件 -->  <linkrel="stylesheet"href="test.css&quo......
  • C语言基础11指针
    指针的引入为函数修改实参提供支持。为动态内存管理提供支持。为动态数据结构提供支持。为内存访问提供另一种途径。指针概述内存地址:系统为了内存管理的方便,将内存划分为一个个的内存单元(1个内存单元占1个字节),并为每一个内存单元进行了编号,内存单元的编号称为该......
  • 三:指针在数组中的应用
    1.使用指针访问数组指针的加减运算可以用来在内存中移动指针的地址。加上一个整数`n`,实际上就是移动了`n`个步长字节。步长是由指针指向的数据类型决定的。例如,假设有一个`int`类型的指针`p`:int*p=(int*)100;那么,执行`p+1`后,指针地址会向后移动`sizeof(in......
  • 【代码随想录】一、数组:3.双指针 - 977.有序数组的平方
    本文为977.有序数组的平方的解法,部分图文参考自代码随想录977.有序数组的平方。1.题目1:977.有序数组的平方1.1.解法1:直接排序classSolution{public:vector<int>sortedSquares(vector<int>&nums){for(inti=0;i<nums.size();i++){n......
  • 3 分钟带你了解 AI Agent(智能体)基础篇
    前言AIAgent(人工智能代理/智能体)绝对是2024上半年一个爆火的话题。从GoogleTrends图中可见一斑。尤其是在中国区,不得不说是真的卷,直接干到了100,是第二名的近10倍。老王最近花费了大量的时间进行学习与研究,期间也在智能体开发平台成功搭建了一些有趣的AIAgent,......
  • Go 语言中的方法接收者自动转换机制:深入理解与实际应用
    在Go语言中,方法接收者可以是值接收者或指针接收者,而Go为开发者提供了一个方便的功能:自动接收者类型转换。这个功能使得我们在调用方法时可以更加灵活,不必担心接收者类型是否完全匹配。然而,尽管这个机制带来了便利,但开发者仍然需要注意方法接收者类型的选择,因为它们在功能、性......