当前位置: 首页 > article >正文

【重生之我要苦学C语言】深入理解指针6

深入理解指针6

sizeof和strlen的对比

sizeof

操作符
整型:

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

在这里插入图片描述

字符串:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char arr[] = "abcdef";
	//a b c d e f \0
	printf("%zd\n", sizeof(arr));
	return 0;
}

输出为 7

strlen

库函数
只能求字符串长度

size_t strlen(const char* str);

strlen统计的是str后,\0之前字符串的个数
strlen函数会一直向后找\0字符,直到找到为止,可能存在越界查找

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
	char arr[] = "abcdef";
	//a b c d e f \0
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", strlen(arr));
	return 0;
}

输出为:

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
	char arr[] = { 'a','b','c' };
	//a b c 
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", strlen(arr));
	return 0;
}

strlen越界访问

在这里插入图片描述

总结
  • sizeof是操作符
  • strlen是库函数,使用时需要包含string.h
  • sizeof计算操作数所占内存大小,单位是字节
  • strlen是求字符串长度的,统计的是\0之前字符的个数
  • sizeof不关注内存中存放什么数据
  • sizeof关注内存中是否有\0,如果没有\0,就会持续往后找,可能会越界

数组和指针中sizeof和strlen辨析

1

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int a[] = { 1,2,3,4 };
	printf("%zd\n", sizeof(a));//16
	printf("%zd\n", sizeof(a + 0));//X86——4 X64——8
	//a做为数组名,并未单独放在sizeof内部,a是数组首元素的地址,a+0是数组首元素的地址
	printf("%zd\n", sizeof(*a));//4
	//a是数组首元素的地址 *a首元素
	printf("%zd\n", sizeof(a + 1));//X86——4 X64——8
	//第二个元素的的地址
	printf("%zd\n", sizeof(a[1]));//4
	//a[1]第二个元素
	printf("%zd\n", sizeof(&a));//X86——4 X64——8
	//&a整个数组的地址,是地址,长度就是4/8个字节
	//&a+1跳过16个字节
	printf("%zd\n", sizeof(*&a));//16 sizeof(a)
	printf("%zd\n", sizeof(&a + 1));//X86——4 X64——8
	printf("%zd\n", sizeof(&a[0]));//X86——4 X64——8
	printf("%zd\n", sizeof(&a[0] + 1));//X86——4 X64——8
	return 0;
}

数组名的理解:
数组名是数组首元素的地址,但是有两个例外:
1.sizeof(数组名),数组名表示整个数组
2.&数组名,数组名表示整个数组

2

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", sizeof(arr));//6
	//计算整个数组的大小
	printf("%zd\n", sizeof(arr+0));//X86——4 X64——8
	//首元素地址
	printf("%zd\n", sizeof(*arr));//1
	//首元素
	printf("%zd\n", sizeof(arr[1]));//1
	//第二个元素
	printf("%zd\n", sizeof(&arr));//X86——4 X64——8
	//数组的地址
	printf("%zd\n", sizeof(&arr+1));//X86——4 X64——8
	printf("%zd\n", sizeof(&arr[0]+1));//X86——4 X64——8
	return 0;
}

3

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//随机值 strlen找\0
	printf("%d\n", strlen(arr+0));//随机值
	printf("%d\n", strlen(*arr));//*arr——'a'——97
	//strlen把97当成地址,非法访问 error
	printf("%d\n", strlen(arr[1]));//error
	printf("%d\n", strlen(&arr));//随机值
	printf("%d\n", strlen(&arr+1));//随机值
	printf("%d\n", strlen(&arr[0]+1));//随机值
	return 0;
}

4

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char arr[] = "abcdef";
	//a b c d e f \0
	printf("%zd\n", sizeof(arr));//7
	printf("%zd\n", sizeof(arr+0));//X86——4 X64——8
	printf("%zd\n", sizeof(*arr));//1
	printf("%zd\n", sizeof(arr[1]));//1
	printf("%zd\n", sizeof(&arr));//X86——4 X64——8
	printf("%zd\n", sizeof(&arr+1));//X86——4 X64——8
	printf("%zd\n", sizeof(&arr[0]+1));//X86——4 X64——8
	return 0;
}

5

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
	char arr[] = "abcdef";
	printf("%zd\n", strlen(arr));//6
	printf("%zd\n", strlen(arr+0));//6
	printf("%zd\n", strlen(*arr));//error
	printf("%zd\n", strlen(arr[1]));//error
	printf("%zd\n", strlen(&arr));//6
	//&arr——char(*)[7]
	//strlen(const char* str)警告
	printf("%zd\n", strlen(&arr+1));//随机值
	//&arr+1跳过整个数组
	printf("%zd\n", strlen(&arr[0]+1));//5
	return 0;
}

6

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char* p = "abcdef";
	printf("%zd\n", sizeof(p));//X86——4 X64——8
	//计算的是p这个指针变量的大小
	printf("%zd\n", sizeof(p+1));//X86——4 X64——8
	//p+1是第二个元素的地址
	printf("%zd\n", sizeof(*p));//1
	printf("%zd\n", sizeof(p[0]));//X86——4 X64——8
	printf("%zd\n", sizeof(&p));//X86——4 X64——8
	printf("%zd\n", sizeof(&p+1));//X86——4 X64——8
	printf("%zd\n", sizeof(&p[0]+1));//X86——4 X64——8
	return 0;
}

7

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
	char* p = "abcdef"
	printf("%zd\n", strlen(p));//6
	printf("%zd\n", strlen(p+1));//5
	printf("%zd\n", strlen(*p));//error
	printf("%zd\n", strlen(p[0]));//error
	printf("%zd\n", strlen(&p));//随机值
	printf("%zd\n", strlen(&p+1));//随机值
	printf("%zd\n", strlen(&p[0]+1));//5
	return 0;
}

二维数组中sizeof和strlen辨析

8

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int a[3][4] = { 0 };
	printf("%zd\n", sizeof(a));//48
	//a数组名,单独放在sizeof里,表示整个数组,计算的是整个数组的大小
	printf("%zd\n", sizeof(a[0][0]));//4
	//a[0][0]第一行第一个元素
	printf("%zd\n", sizeof(a[0]));.//16
	//a[0]第一行数组名,单独放在sizeof内部,计算的是第一行的大小
	printf("%zd\n", sizeof(a[0]+1));//X86——4 X64——8
	//a[0]不是单独放在sizeof内部,a[0]就是首元素的地址,a[0][0]的地址,a[0]+1第一行第二个元素的地址
	printf("%zd\n", sizeof(*(a[0]+1)));//4 
	//a[0]+1是a[0][1]的地址,*(a[0]+1)就是a[0][1]
	printf("%zd\n", sizeof(a+1));//X86——4 X64——8
	//a是二维数组第一行的地址 a+1是第二行的地址
	printf("%zd\n", sizeof(*(a+1)));//16
	//计算的是第二行的大小
	printf("%zd\n", sizeof(&a[0]+1));//X86——4 X64——8
	//&a[0]第一行的地址 &a[0]+1第二行的地址
	printf("%zd\n", sizeof(*(&a[0]+1)));//16
	printf("%zd\n", sizeof(*a));//16
	//a是二维数组第一行的的地址 *a就是行,计算的是第一行的大小
	printf("%zd\n", sizeof(a[3]));//16
	//sizeof在计算的时候是根据类型计算长度的,即使写的是一个表达式,编译器也会推算出最后的类型来计算长度
	return 0;
}

指针运用笔试题

例1

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int a[5] = { 1,2,3,4,5 };
	int* ptr = (int*)(&a + 1);
	printf("%d %d", *(a + 1), *(ptr - 1));
	//2 5
	return 0;
}

例2 指针+1

X86环境下

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p=(struct Test*)0x100000;
int main() {
	printf("%p\n", p + 0x1);
	//结构体指针+1跳过20个字节 0x100014
	printf("%p\n", (unsigned long)p+0x1);
	//0x100001
	printf("%p\n",(unsigned int*) p + 0x1);
	//跳过四个字节 0x100004
	return 0;
}

例3

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int a[3][2] = { (0,1),(2,3),(4,5) };
	//逗号表达式      1    3    
	//               5    0
	//               0    0
	int* p;
	p = a[0];
	printf("%d", p[0]);
	//1
	return 0;
}

例4 指针-指针

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int a[5][5];
	int(*p)[4];
	//数组指针,指向的数组里有四个int类型的元素
	p = a;
	printf("%p %d\n", &p[4][2]-&a[4][2],&p[4][2]-&a[4][2]);
	//FFFFFFFC -4
	return 0;
}

在这里插入图片描述

例5

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

例6

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char* a[] = { "work","at","c" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	//at
	return 0;
}

例7

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	char* c[] = { "ENTER","NEW","POINT","FIRST"};
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);//POINT
	return 0;
}

在这里插入图片描述

	printf("%s\n", *-- * ++cpp + 3);//ER

在这里插入图片描述

	printf("%s\n", *cpp[-2] + 3);//ST
	//**(cpp-2)+3

在这里插入图片描述

printf("%s\n", cpp[-1][-1] + 1);//EW
//*(*cpp-1)-1)+1

在这里插入图片描述

END……

世界上有太多孤独的人,害怕先踏出第一步。
There are too many lonely people in the world who afraid to take the first step.
——《绿皮书》

http://www.kler.cn/a/395601.html

相关文章:

  • 博物馆实景复刻:开启沉浸式文化体验的新篇章
  • Python期末复习 | 列表、元组、字典、集合与字符串 | 代码演示
  • 虎扑APP数据采集:JavaScript与AJAX的结合使用
  • 《Probing the 3D Awareness of Visual Foundation Models》论文解析——多视图一致性
  • Exploring Defeasible Reasoning in Large Language Models: A Chain-of-Thought A
  • Android 项目依赖库无法找到的解决方案
  • 无人机检测车辆——多目标检测
  • Postman接口测试(断言、关联、参数化、输出测试报告)
  • Win11 终端执行 python xxx.py 没反应
  • 241115
  • 《Java核心技术 卷I》图形界面事件处理适配器类
  • Unix进程
  • 杰控通过 OPCproxy 获取数据发送到服务器
  • 嵌入是开发 之TCP网络编程(一)
  • 界面控件DevExpress Blazor UI v24.1新版亮点 - 全新PDF Viewer等组件
  • SQL Server Service Broker完整示例
  • 【代码大模型】Is Your Code Generated by ChatGPT Really Correct?论文阅读
  • react 中 memo 模块作用
  • 深入理解BERT模型:BertModel类详解
  • [Mysql基础] 表的操作
  • Qt 的 QThread:多线程编程的基础
  • Uniapp 引入 Android aar 包 和 Android 离线打包
  • 跟李笑来学美式俚语(Most Common American Idioms): Part 01
  • 网络安全---安全见闻2
  • Shell编程-2
  • (三十三)队列(queue)