C语言 #字符指针

.NET(C#) 中使用指针 在 .NET 中,C# 默认情况下是一种安全的、不支持直接使用指针的语言。然而,C# 支持在特定情况下使用不安全代码(即可以使用指针的代码)。使用不安全代码意味着放弃了 C# 和 .NET 运行时提供的一些安全保障,因此必须谨慎使用。不安全代码可能会增加程序出错的风险,特别是与内存管理相关的错误,如堆损坏、内存泄漏等。指针操作通常只在性能至关重要的情况下使用,或者在需要与系统级别或非托管代码互操作时使用。 阅读详情


前言

路漫漫其修远兮,武将上下而求索;

以例子为导向来分析字符指针的中存的是什么,以及常量字符串在内存中是如何存储的。


一、指针概念简述

想要详细地了解指针的概念可以戳此链接(详细的万字讲解):C语言 底层逻辑详细阐述指针(一)万字讲解 #指针是什么? #指针和指针类型 #指针的解引用 #野指针 #指针的运算 #指针和数组 #二级指针 #指针数组_c语言底层逻辑-优快云博客

本文就简单地回顾指针的一些基础知识:

1、指针本身就是地址,内存单元的编号为地址,而地址又称为指针;指针在口语上认为是指针变量、是用来存放地址的变量,每个地址都唯一地标识内存中一块内存空间;

2、指针的大小是固定的4byte\8byte (32位平台或者64位平台)

3、指针是有类型的,其类型不会决定其在内存中占据的空间,而是决定了当解引用此指针变量时有多少字节的访问内存的权限;以及指针变量+、-整数的步长

4、指针的运算

二、字符指针

顾名思义,字符指针就是指针变量指向的对象是字符类型,即指针变量的类型为 char* ;

单个字符的指针创建,代码如下:

#include<stdio.h>

int main()
{
	char ch = 'a';
	char* p = &ch;//此*代表着变量p 为指针变量
	*p = 'b';

	return 0;
}

字符指针可以存放一个字符变量的地址,那么字符串的地址该如何存放呢?

先来看一下整型的例子: 

int a = 10 ;

int b = a + 2;

"a+2" 是一个表达式的话,那么此表达式就一定有自己的值,然后再将此值赋给b ;

注:表达式有两个属性:值属性 和 类型属性

即 "a+2" 的结果为12,那么12就为其值属性;2 为int 类型,变量a 为int 类型,那么 "a+2"此表达式 的类型为int 类型。

eg. char * p = "abcdefg" ;

若将字符串"abcdefg"当作表达式,那么将它赋给指针变量p 的是什么呢?

  • 在x86环境下,指针变量p 中只能存放大小为4byte 的地址;而显然整个字符串在内存中是连续存放的,即不止占用一个内存单元空间,所以整个字符串会有多个地址;那么指针p是存放不下整个字符串的地址;

字符串"abcdefg"赋给指针p是其首字符 'a '的地址。

而函数printf 的占位符%s 会通过字符串的首字符地址而找到整个字符串;

我们来看一下打印字符串,代码如下:

#include<stdio.h>

int main()
{
	char ch[10] = "abcdefg";
	char* p = "abcdefg";
	char* p1 = ch; //将数组的首元素地址存放起来

	printf("%s\n", "abcdefg");
	printf("%s\n", ch);
	printf("%s\n", p);
	printf("%s\n", p1);

	printf("字符串地址=%p\n", "abcdefg");
	printf("指针p中存放的地址=%p\n", p);
	printf("指针p1中存放的地址=%p\n", p1);

	return 0;
}

代码运行结果如下:

分析:字符串的创建是用字符数组创建的,我们打印字符串一般采用 printf("%s\n", "abcdefg"); 这种方式,或者将字符串存在数组中,然后对此数组进行打印,即printf("%s\n",ch);

这时候你可能就会有疑问了,数组名可以理解为整体的数组也可以理解为其首元素的地址,于是我们就不清楚:

  • 是因为printf函数的占位符%s 只要得到字符串的首字符地址就会一直往后访问直到遇到 '\0' 
  • 还是因为根据的整体字符串"abcdefg"或者整个数组而打印出来整个字符串;

于是我们尝试将数组的首元素地址存放到指针p1中,我们会发现 printf("%s\n", p1);也可以实现打印字符串 "abcdefg" ,那么此时似乎就明显地感觉:打印字符串只要有其首字符的地址即可;

将字符串的地址存放到指针p中,指针p中存放的是整个字符串的地址吗?

  • 我们知道一个字符在内存中占 1 byte 的空间,而一个内存单元有一个地址,如果是想存放整个字符串的地址,就会存多个地址,但是指针变量在x86环境下只向内存申请了4byte 来存放该地址,所以就无法存放整个字符串的地址;printf("指针p中存放的地址=%p\n", p);的结果看以上代码运行结果,可知p中存放的为一个地址,即字符串首元素的地址;

我们将以上的代码又运行了一次:

我们不难发现,字符串的地址未改变,但是数组首元素的地址改变了

  • 这是因为 "abcdefg" 是一个常量字符串,即不能被修改的字符串;字符串是存放在内存中的常量区,在编译期间编译器便指派了地址;

常量区中的值只能读取而不能修改,所以当将此存在常量区的字符串的地址存到指针变量中,为以防对此指针变量解引用而对此字符串进行修改,于是应该优化写作: const char* p = "abcdefg";

注:const 修饰指针变量:(eg. char* p = "abcdefg"; )

1、当 const 放在 * 的左边,有两中写法:

  • 一是 const  char* p = "abcdefg";
  • 二是 char const * p = "abcdefg";

表示 *p 即指针变量p 指向的对象,const 修饰指针p指向的对象也就是说指针p 指向的对象是常变量,即指针p 指向的对象不可被修改;

2、当const 放在* 的右边,写作:

  • char* const p = "abcdefg";

表示指针变量 p是个常变量即存放在指针p中的地址不可修改;

字符指针有两种的表示形式:

1、const 不修饰

  • char* p = "abcdefg";

2、const 修饰

  • const char* p = "abcdefg";   
  •  char const * p = "abcdefg";

三、字符在内存中的存储

我们按照例子来分析:

#include<stdio.h>

int main()
{
	const char* p1 = "abcdef";
	const char* p2 = "abcdef";

	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	if (p1 == p2)
		printf("p1==p2\n");
	else
		printf("p1!=p2\n");

	if (arr1 == arr2)
		printf("arr1==arr2");
	else
		printf("arr1!=arr2");

	return 0;
}

代码运行结果:

分析:常量字符串 ”abcdef“ 存放在内存中的常量区,常量区只能读取而不能对其进行修改;

为什么常量字符串存在常量区?

  • 因为既然常量字符串不能被修改,那么这样的常量就没必要存多份,只要有一份,并且谁都不能去修改它;即常量字符串在内存中存一份便足以够用了;字符串是存放在内存中的常量区,在编译期间编译器便指派了地址;当是一个指针来存放该常量字符串的地址的时候,指针中存放的便是该字符串首元素在常量区中的地址;故而指针p1 与指针 p2 中存放的地址相同,即p1==p2;
  • 而如若是一个数组想要来存放该字符串,编译器便会先将存放在常量区的字符串拷贝放入到此数组之中,数组(假设该数组为局部变量)的空间是在其所在函数的函数栈帧的开辟的时候便确定了;从另外一个角度来看:数组创建时会向内存申请相对的大小空间来存放数组中的数据;而数组arr1 和 数组arr2 都会向内存申请空间来存放其数据,而每个内存单元的编号都不相同,所以就会导致不同空间的地址也不相同;再者,数组名代表着首元素的地址,所以 arr1 ! = arr2 ;

注:常量字符串不需要创建;代码中出现字符串 eg.const char* p1 = "abcdef"; 程序在编译时期:编译器会在只读数据区中放 abcdef \0 ,将" abcdef "当作常量字符来看待;而此时,只要将常量字符的起始地址交给一个指针去维护即可;同理,因为在编译期间编译器便为常量字符串在常量区指派了地址,故而想要在数组中放入常量字符串会将存放在常量区的字符串拷贝放入数组所占据的空间;


总结

1、字符指针就是指针变量指向的对象是字符类型,即指针变量的类型为 char* ;

2、const char* p = "abcdefg"; \ char const * p = "abcdefg"; 指针p中存放的是常量字符串在常量区存放的首字符 'a' 的地址

3、常量字符串存放在内存中的常量区,常量区中的数据只能读取而不能被修改。

指针进阶之字符指针(超详细) 指针进阶之字符指针,讲到懂 阅读详情

相关推荐

C语言之字符指针

第一种:指向一个字符 第二种:指向一个数组 第三种:指向一个字符常量 对于char*ch="hello,world"这行代码,很多小伙伴会认为是把hello,world放到字符指针ch里面,但其实是把字符串hello,world,首字符的地址放到了ch中. ......

m0_64365419的博客 5756

字符指针

2019-8-9字符指针 ①字符指针:指向字符型数据的指针变量。每个字符串在内存中都占用一段连续的存储空间,并有唯一确定的首地址。即将字符串的首地址赋值给字符指针,可让字符指针指向一个字符串。 ② char *ptr = "Hello";//将保存在常量存储区的"Hello"的首地址赋值给ptr 与 char *ptr; ptr = "Hello";//是等价的,注意不能理解为将字符串赋值给ptr...

小菜鸡 3万+

Win10下ISE14.7安装避坑全记录:从License加载失败到ChipScope连不上,我踩过的雷都在这了

本文详细记录了在Win10系统下安装ISE14.7时遇到的常见问题及解决方案,包括License加载失败、IMPACT闪退、ChipScope连接故障等。通过实际案例和步骤解析,帮助用户避开安装陷阱,确保FPGA开发工具顺利运行。特别针对license问题提供了兼容性设置和文件修改的实用技巧。

weixin_42683394的博客 225

字符串--字符指针、字符串的访问和输入/输出(字符串空格问题,输入带双引号的字符串)

其实,在前面几个程序都存在一种容易被忽略的问题,即如果用户没有听从括号内的提示信息的指示,键入的字符数超过了数组name的大小12,那么多出来的那些字符就有可能重写内存的其他区域,导致程序出错。例如,在前面定义的字符数组str中,str[0]就表示第1个字符’H’,str[1]表示第2个字符’e’,依此类推,可以通过下标为i的元素str[i]来访问存放于数组中的第i+1个字符。因为数组名是一个地址常量,所以str的值是不可修改的,但ptr的值(即ptr的指向)可以被修改,ptr所指向的字符串也可以被修改。

ww1425408527的博客 7274

华为ENSP虚拟网络与本地物理网卡高效桥接实战指南

本文提供了一份详细的华为ENSP虚拟网络与本地物理网卡桥接实战指南。通过清晰的四步操作,帮助用户打破虚拟实验环境的“孤岛”限制,实现ENSP设备与真实局域网及互联网的互通,从而进行更真实的协议测试、软件升级和混合网络环境搭建。

qsc90123456的博客 537

Kali Linux渗透测试:蚁剑(AntSword)三种安装方法与避坑指南

WebShell管理是渗透测试与网络安全攻防演练中的关键技术环节,它允许安全人员在获得初步访问权限后,对目标系统进行文件管理、命令执行和数据库操作等深度控制。其核心原理是通过在Web服务器上植入特定脚本,建立一条隐蔽的远程管理通道。在实战中,一个高效、稳定的WebShell管理工具能极大提升后渗透阶段的工作效率与成功率。蚁剑(AntSword)作为一款功能强大的国产开源工具,凭借其插件化架构和图形化界面,成为众多安全研究人员的首选。本文将聚焦于如何在渗透测试专用操作系统Kali Linux上部署蚁剑,详细对

weixin_34413103的博客 414

C语言 进阶指针笔记博客 #字符指针#数组指针#指针数组对进阶指针的详细解析

通过**“顾名思义”与“内存本质”**双维度,系统梳理从字符指针、数组指针到函数指针数组的逻辑脉络。教你利用优先级与结合性拆解《C陷阱与缺陷》中的复杂声明,看透指针步长与传参本质,助你彻底通关 C 语言底层逻辑,跳出指针陷阱。

2501_91286341的博客 639

EGO_Plannerv2代码学习(一):栅格建图之V1 V2的区别

最近在尝试将高飞老师的集群规划器部署到真实无人机上跑一下,开这个新帖记录下学习过程中的问题和想法。

qq_41069236的博客 5753

椋鸟C语言笔记#20:指针数组、指针模拟二维数组、数组指针、二维数组传参的本质、字符指针与字符串

萌新的学习笔记,写错了恳请斧正。

椋鸟的博客小窝 210

微信小程序 - 获取用户头像昵称等信息(带授权检测)

前言 接口调整官方文档:https://developers.weixin.qq.com/community/develop/doc/0000a26e1aca6012e896a517556c01 在以前,是否授权可以直接弹出询问用户,但现在微信更改了策略,必须由用户点击按钮触发。下面将用代码来实现用户授权及获取用户信息。 功能介绍 无论确认授权还是拒绝授权,都会跳转对应页面,不让用户卡在界面。 点击授权后,下次不在出现授权页面了,如果拒绝,下次依然出现。 以下代码可直接复制粘贴,具体功能如下:

🏆 前端领域优质创作者 1万+

AI:270-基于ASFF改进YOLOv8检测头的多尺度特征融合方法详解与实战

ASFF是一种基于自适应特征融合的策略,能够动态调整不同尺度特征的融合权重,适应场景中不同大小的目标。传统的YOLOv8检测头使用固定的特征融合策略,而ASFF则通过引入学习参数,使得网络能够根据输入图像的特征自适应地选择不同尺度特征的重要性。这一策略对于检测小目标或尺度变化大的目标具有显著优势。本文提出了一种改进YOLOv8检测头的新方法,通过引入自适应空间特征融合模块(ASFF),有效提升了多尺度目标检测的性能,特别是在小目标检测任务中的表现。

一键难忘的博客 3913

C语言 带参数宏定义中 # 和 ## 知识点总结、代码分析

目录 一、宏定义中 “#”知识点 1、直接转换字符串,不展开。 2、转换出的结果一定是“字符串”。 二、宏定义中 ## 知识点 1、应用场景 2、“##”的作用是将 左右两边的参数做整体字符串拼接替换 3、经过 ## 替换后的内容必须 有一个 同名的 变量与之对应。 4、 只拼接,不展开。 5、## 操作 动态函数指针 案例代码 一、宏定义中 “#”知识点 #的...

猪哥的专栏 4269

【图像去噪】论文复现:降维打击!图像对输入变成像素对输入!Pytorch实现Noise2Void(N2V),基于U-Net模型训练,简洁明了理解N2V核心思想!附训练好的灰度图和RGB图的模型文件!

论文题目:Noise2Void-Learning Denoising from Single Noisy Images —— Noise2Void -从单个噪声图像中学习去噪【图像去噪】论文精读:Noise2Void-Learning Denoising from Single Noisy Images(N2V)由于源码是tensorflow版本,本文将基于Pytorch复现。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 1356

24.大厂总监带你吃透 C语言字符串存储之谜:指针 vs 数组的内存真相 #总结版 #a1

c语言中,c1指向代码段中的常量,只读不写,且常量相同,指向的地址也相同。中,c2指向堆栈段中的数据,可读可写,相当于把代码端的数据拷贝了出来。

c5dnuser的博客 289

多体动力学分析软件:ADAMS_(15).多体动力学建模与分析实践

1. 在工具栏中选择“Body”工具。2. 在图形窗口中点击鼠标左键选择刚体的中心点。3. 按住鼠标左键拖动,定义刚体的尺寸。4. 在弹出的属性对话框中设置刚体的质量、惯性参数等。关节是连接刚体的关键部件,定义关节时需要选择合适的关节类型并设置关节的参数。约束是对刚体运动的限制,定义约束时需要选择合适的约束类型并设置约束的参数。1. 在主菜单中选择“Model” > “Optimization” > “Objective Function”。

kkchenjj的博客 1311

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

嵌入式C语言高级知识点总结

预处理, 展开头文件/宏替换/去掉注释/条件编译 (test.i main .i)编译(gcc -s), 检查语法,生成汇编 ( test.s main .s)汇编(gcc -c), 汇编代码转换机器码 (test.o main.o)

weixin_56940389的博客 3840

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C语言的细节(不定期更新)

1.字符串换行c语言中,所有的空格、注释、TAB、换行都可以任意写,但是字符串中不可以。如果要换行,就像这样printf("a very very very very""long string");这个是C89以后才支持,老的风格是printf( "a very very / very long line");2 pow函数pow()的返回类型为double,在对整

暗恋的滋味 1403

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

嵌入式高级c语言学习

传递一个值的地址 int a = 10,void fun(int *p)传递一个空间的地址int buf[10];函数返回值静态区:关键字static 会把buf里的局部变量由局部变量存的栈中放在数据(Data)段在静态区,生存周期是整个程序结束2.只读区: char buf[] = "hello world";3.堆区:malloc() ,free() char *s = (char *)malloc(2048);堆区return s;

m0_62995834的博客 901

C语言经典代码——part 28

题目:从键盘输入一些字符,逐个把它们送到磁盘上去,直到输入一个#为止。题目:计算字符串中子串出现的次数。

2303_81838541的博客 486

C语言和gcc笔记

1.C语言中的register关键字只是类型修饰符和const和volatile的地位一样。在C语言中定义register a;用gcc -Wall 编译后会警告type defaults to `int' in declaration of `a',可见register 只是修饰符。 2.在C语言中数组会退化为指针。如下代码 #include #include int main(){

Notebook 1372

C语言中定义变量“#X”,”X##”, “##X” 和“##X##”解析

关于#和## 在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏: 1. #使用 #define WARN_IF(EXP) / do{ if (EXP) / fprintf(stderr, "Warning: " #EXP "/n"); } / wh...

weixin_30417487的博客 760

【C语言练习】编写代码,演示多个字符从两端移动,向中间汇聚

利用C语言编写一个程序,实现多个字符从两端从中间汇聚。

embrace99的博客 192

c语言switch函数映射技巧,C语言宏定义##连接符和#符的使用(MFC就是靠##自动把消息和消息函数对应起来了,借助宏来减少switch case代码的编写量)...

C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念)。下面对常遇到的宏的使用问题做了简单总结。关于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏:#define WARN_IF(EXP) do{ i...

weixin_39616477的博客 502

C //例10.1 从键盘输入一些字符,逐个把它们送到磁盘上去,直到用户输入一个“#”为止。

【代码】C //例10.1 从键盘输入一些字符,逐个把它们送到磁盘上去,直到用户输入一个“#”为止。

Made in Code 760

c语言里的%p的作用,C语言中geiwei=m%10什么意思,求解!

C语言中geiwei=m%10什么意思,求解!以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!C语言中geiwei=m%10什么意思,求解!%运算表示取余数,m%10就把m除以10的余数,实际上就是m的个位数。例如m的值为13,那么m%10的结果就是3。c语言中if(m)什么意思if(m) 如果m是逻辑真if(m=+)是...

weixin_35531779的博客 1785

c语言控制与实现 pdf,c语言的控制输出格式.pdf

1 .转换说明符%a(%A) 浮点数、十六进制数字和 p-(P-) 记数法 (C99)%c 字符%d 有符号十进制整数%f 浮点数 ( 包括 float 和 doulbe)%e(%E) 浮点数指数输出 [e-(E-) 记数法 ]%g(%G) 浮点数不显无意义的零 ...

weixin_42313675的博客 139
上一篇: C语言 数据存储之结构类型 万字讲解#数据类型详细介绍 #整型在内存中的存储 #大小端字节序 #浮点型在内存的存储解析
下一篇: C语言 #指针数组 #数组指针 #数组参数、指针参数
秦少游在淮海
博客等级 码龄3年 1071粉丝 88原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值