C语言字符、字符串

一、c语言字符串的本质

1、char类型数组

c语言没有专门用来存储字符串的变量类型,字符串都是存储在char类型的数组中,char类型的连续空间中每个存储单元存储一个字符,数组末尾以’\0’结束,标志字符串的结束。'\0’是空字符,对应ASCII码值是0。

在这里插入图片描述

c语言字符串一定是以’\0’结束的,所以在定义数组时,至少要预留一个位置用来存储’\0’,也就是说,如果定义一个10个空间的char数组,最多可以用来存储9个字节的字符串。

// 10个空间的char数组,最能只能存储9个字符,要留一个空间存储'\0'结束符
char str[10] = "abcd";

在定义字符串的时候,并不需要认为的添加’\0’,编译器会自动为我们做这一步。

2、字符串和字符

字符串常量"A"和字符常量’A’是不一样的,字符常量’A’的数据类型是char,而字符串常量"A"是一个char类型的数组。另外,字符常量’A’仅由字符’A’组成,而字符串常量"A"是由’A’和’\0’两个字节构成的。

在这里插入图片描述

3、strlen()和sizeof

sizeof 是运算符,它以字节为单位给出对象的大小,strlen()是函数,它给出字符串中的字符长度。

#define NAME "Tom"
char str[10] = "abcd";
printf("sizeof(str) = %zd\n", sizeof(str));		// 10
printf("strlen(str) = %zd\n", strlen(str));		// 4
printf("sizeof(NAME) = %zd\n", sizeof(NAME));	// 4
printf("strlen(NAME) = %zd\n", strlen(NAME));	// 3

上面代码定义的NAME是一个字面量的字符串,实际上编辑器给这个字符串自动加上了’\0’标识。sizeof计算的str结果为10,表示的是char数组实际定义的大小,strlen(str)计算的数值为4,strlen(str)表示的是字符串真实的字符数量,它并不会包含’\0’这个标识符。sizeof(NAME)计算的空间大小为4,实际上是’T’、‘o’、‘m’、‘\0’共四个字符,strlen(NAME)只是计算字符串实际的字符数量,它遇到’\0’,则认为字符串结束了。

二、定义字符串

1、字符串字面量

在程序中,用双引号括起来的内容称为字符串字面量,也叫作字符串常量。它在内存中存储的内容包括双引号中的字符和编译器自动加入末尾的’\0’标识符。

#define NAME "Tom"
char words[10] = "abcde";
const char * pt = "123456789";
printf("a1b2c3");

“Tom”、“abcde”、“123456789”、"a1b2c3"都是字符串常量。

字符串常量属于静态存储类别,这说明如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命期内存在,即使函数被调用多次。用双引号括起来的内容被视为指向该字符串储存位置的指针,类似于把数组名作为指向该数组位置的指针。

printf("%s, %p, %c\n", "ab", "cd", *"efgh");//ab, 000000013FE3AE88, e

printf()根据%s 打印出字符串 ab,根据%p 打印出一个地址000000013FE3AE88,"cd"代表字符串首字符的地址。最后,*"efgh"表示该字符串所指向地址上储存的值,应该是字符串*"efgh"的第一个字符。

2、字符串数组和初始化

定义字符串数组时,必须让编译器知道需要多少空间,一种方法是用足够空间的数组储存字符串。

const char str[40] = "I like apple."; // const修饰,不能修改这个字符串

相较于标准的数组初始化形式简单了许多。

const char str[40] = {'I', ' ', 'l', 'i', 'k', 'e', ' ', 'a', 'p', 'p', 'l', 'e', '.', '\0'};

注意最后的空字符。没有这个空字符,这就不是一个字符串,而是一个字符数组。在指定数组大小时,要确保数组的元素个数至少比字符串长度多1(为了容纳空字符)。所有未被使用的元素都被自动初始化为0(这里的0指的是
char形式的空字符,不是数字字符0)。

省略数组初始化声明中的大小,编译器会自动计算数组的大小:

char str[] = "I like apple."; // const修饰,不能修改这个字符串
printf("sizeof(str):%zd\n", sizeof(str));	// 14
printf("strlen(str):%zd\n", strlen(str));	// 13

字符数组名和其他数组名一样,是该数组首元素的地址。str == &str[0]、*str == ‘I’、*(car+3) == car[3] == ‘i’。

3、数组和指针

初始化数组是把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针。

先对两种形式进行声明:

const char ar[] = "I like apple.";	// 数组方式声明
const char * pt = "I like apple.";	// 指针方式声明

两个声明都表明pt和ar都是该字符串的地址,带双引号的字符串决定了预留给字符串的存储空间。但是这两种声明形式并不完全相同。

以上面的声明为例,数组形式的ar在计算机的内存中分配为一个内含14个元素的数组(共13个字符+末尾的空字符’\0’),每个元素被初始化为字符串字面量对应的字符。字符串储存在静态存储区中,当程序在开始运行时才会为该数组分配内存。这个时候才将字符串拷贝到数组中。需要明确,此时字符串有两个副本,一个是存储在静态内存中的字符串字面量,另一个是储存在ar数组中的字符串。编译器会把数组名ar识别为该数组首元素地址(&ar[0])的别名。要注意,在数组形式中,ar是地址常量,不能更改ar,如果改变了ar,则意味着改变了数组的存储位置,允许ar+1这样的操作,标识数组的下一个元素,但是不允许进行++ar这样的操作。

指针形式pt也使得编译器为字符串在静态存储区预留14个元素的空间。在程序开始执行时,字符串的地址储存到该指针变量中。指针变量pt最初指向该字符串的首字符,它的值可以改变。也可以使用递增运算符。比如++pt将指向字符串的第2 个字符。字符串字面量被视为const数据,由于pt指向这个const数据,因此不能用pt改变它所指向的数据,所以在以指针形式声明字符串的时候要用const修饰,代表不能修改指针所指向的值。

4、数组和指针的区别

先对两种形式进行声明:

char ar[] = "I like apple.";	// 数组方式声明
const char ar[] = "I like apple.";	// 数组方式声明 const修饰

const char * pt = "I like apple.";	// 指针方式声明必须使用const

数组名ar是常量,因此不可以改变ar的指向,如++ar操作是不合法的。数组声明方式可以用const修饰,也可以不使用const修饰,使用const则代表数组里面的字符串数组是不可以修改内容的,只可读,不可写。

指针名pt是变量,因此可以改变pt的指向,如++pt操作是可以使用的。指针方式声明必须使用const,因为指针指向的是静态存储区的字符串字面量,内容不可修改。

看接下来的操作:

pt = ar;	// 合法操作,pt指向数组ar

ar = pt;	// 非法操作,ar地址不可以修改

pt = ar;不会导致pt指向的字符串消失,这样做只是改变了储存在pt中的地址。除非已经保存了"I like apple."的地址,否则当pt指向别处时,就无法再访问该字符串。

为什么不能按照如下定义:

char * pt = "I like apple.";  // 不推荐的定义方式,且VS2019报错

"I like apple."是字符串字面量,是一段不可修改的数据,char*定义的pt,从语法上讲是可以修改指针指向数据的,二者是矛盾的,编译器大概率会报错(VS2019会报错),因此推荐使用const。当想要修改字符串的时候,可以使用非const数组初始化为字符串字面量,因为数组获得的是原始字符串的副本,因此不会导致类似的问题。

5、字符串数组

定义字符串数组的两种方式:

const char *arr1[4] = {
    "I like apple.",
	"Hello!", 
    "Yes.",
	"This is a string."
};

char arr2[4][20] = {
    "I like apple.",
	"Hello!", 
    "Yes.",
	"This is a string."
};

arr1和arr2实现的功能是相似的,两者的初始化方式相同,它们都初始化了4个字符串,arr1[0]和arr2[0]可以得到相同的字符串,双下标都可以得到相应的字符。

它们也有区别,arr1数组是一个内含4个指针的数组,共占用36字节(64位系统,一个指针占8个字节),而arr2是一个内含4个数组的数组,每个数组内含20个char类型的值,共占用80字节。虽然arr1[0]和arr2[0]都分别表示一个字符串,但arr1和arr2的类型并不相同,arr1中的指针指向初始化时所用的字符串字面量的位置,这些字符串字面量被储存在静态内存中,而arr2 中的数组则储存着字符串字面量的副本,所以每个字符串都被储存了两次。此外,arr2分配内存的使用率较低,arr2中的每个元素的大小必须相同,而且必须是能储存最长字符串的大小。

arr1数组的指针元素所指向的字符串不一定储存在连续的内存中,而arr2数组中的数据一定存储在一段连续的内存中。arr1中的指针指向的字符串字面量不能更改,而arr2中的内容可以更改。

三、字符串中sizeof的思考

下列代码:

char str[] = "I like apple.";
printf("sizeof(str) = %zd\n", sizeof(str));			// 字符串占用字节数	14
printf("sizeof(&str[0]) = %zd\n", sizeof(&str[0]));	// 指针占用字节数	 8

这是因为str是内含14个char类型的值,每个值占1字节,所以整个str的大小是14字节。而&str[0])是指向字符串第一个字符的指针,64位系统指针类型占8个字节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/364645.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源编辑器:ONLYOFFICE文档又更新了!

办公软件 ONLYOFFICE文档最新版本 8.0 现已发布:PDF 表单、RTL、单变量求解、图表向导、插件界面设计等更新。 什么是 ONLYOFFICE 文档 ONLYOFFICE 文档是一套功能强大的文档编辑器,支持编辑处理文本文档、电子表格、演示文稿、可填写的表单、PDF&#…

大语言模型之LlaMA系列- LlaMA 2及LLaMA2_chat(上)

LlaMA 2是一个经过预训练与微调的基于自回归的transformer的LLMs,参数从7B至70B。同期推出的Llama 2-Chat是Llama 2专门为对话领域微调的模型。 在许多开放的基准测试中Llama 2-Chat优于其他开源的聊天模型,此外Llama 2-Chat还做了可用性与安全性评估。 …

IP定位如何进行业务风控反欺诈

IP地址作为接入互联网的唯一标识,分析其归属地及网络类型等多维度信息,帮助识别虚假流量和欺诈账号,保障账号和交易安全,帮助企业持续优化风控与反欺诈模型,降低经济损失。 交易聚集分析 通过IP地址数据服务得到的交易…

Pytorch从零开始实战18

Pytorch从零开始实战——人脸图像生成 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——人脸图像生成环境准备模型定义开始训练可视化总结 环境准备 本文基于Jupyter notebook,使用Python3.8,Pytorch2.0.1cu118&#…

Linux下gcc的使用与程序的翻译

gcc和程序的翻译过程 gcc介绍程序的翻译过程预编译编译汇编链接 命令行式宏定义 gcc介绍 gcc是一款编译C语言编译器,可以把我们用vim写的代码编译成可执行程序。编译C用g进行编译,C的文件后缀是test.cc或test.cpp或test.cxx 如果要安装g就执行以下命令 …

一文详解docker swarm

文章目录 1、简介1.1、涉及到哪些概念?1.2、需要注意什么? 2、集群管理2.1、创建集群2.2、将节点加入集群2.3、查看集群状态。2.4、将节点从集群中移除2.5、更新集群2.6、锁定/解锁集群 3、节点管理4、服务部署4.1、准备4.2、服务管理4.2.1、常用命令4.2…

TCP 连接掉线自动重连

文章目录 TCP 连接掉线自动重连定义使用连接效果 TCP 接收数据时防止掉线。TCP 连接掉线自动重连。多线程环境下TCP掉线自动重连。 欢迎讨论更好的方法! TCP 连接掉线自动重连 定义 定义一个类,以编写TCP连接函数Connect(),并且&#xff1a…

分发糖果[困难]

优质博文:IT-BLOG-CN 一、题目 n个孩子站成一排。给你一个整数数组ratings表示每个孩子的评分。你需要按照以下要求,给这些孩子分发糖果: 【1】每个孩子至少分配到1个糖果。 【2】相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩…

JavaScript基础五对象 内置对象 Math.random()

内置对象-生成任意范围随机数 Math.random() 随机数函数, 返回一个0 - 1之间,并且包括0不包括1的随机小数 [0, 1) 如何生成0-10的随机数呢? Math.floor(Math.random() * (10 1)) 放大11倍再向下取整 如何生成5-10的随机数&…

【智能算法】11种混沌映射算法+2种智能算法示范【鲸鱼WOA、灰狼GWO算法】

1 主要内容 混沌映射算法是我们在智能算法改进中常用到的方法,本程序充分考虑改进算法应用的便捷性,集成了11种混合映射算法,包括Singer、tent、Logistic、Cubic、chebyshev、Piecewise、sinusoidal、Sine、ICMIC、Circle、Bernoulli&#xf…

css实现按钮边框旋转

先上效果图 本质&#xff1a;一个矩形在两个矩形互相重叠遮盖形成的缝隙中旋转形成&#xff0c;注意css属性z-index层级关系 直接上代码 <div class"bg"><div class"button">按钮</div></div><style>.bg {width: 100%;heigh…

数字图像处理(实践篇)四十一 OpenCV-Python 使用sift算法检测图像上的特征点实践

目录 一 涉及的函数 二 实践 2004年,D.Lowe在论文Distinctive Image Features from Scale-Invariant Keypoints中提出了一种新算法,即尺度不变特征变换 (SIFT),该算法提取关键点并计算其描述符。SIFT提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置尺度和方向…

绝地求生:“龙腾”通行证和新空投任务内容一览:二十级依然有图纸!

大家好&#xff0c;27.2版本终于更新完了&#xff0c;先为大家带来这次龙腾通行证的详细内容&#xff0c;显放上详细的兑换点数大家可以慢慢看。 省流: 通行证分支3仍然可解锁图纸和500G-COIN奖励&#xff0c;空投任务也可以通过做很简单的游戏任务70代币兑换获得1张图纸。 这次…

main函数中参数argc和argv用法解析

1 基础 argc 是 argument count 的缩写&#xff0c;表示传入main函数的参数个数&#xff1b; argv 是 argument vector 的缩写&#xff0c;表示传入main函数的参数序列或指针&#xff0c;并且第一个参数argv[0]一定是程序的名称&#xff0c;并且包含了程序所在的完整路径&…

vue 发布自己的npm组件

1、在项目任意位置创建index.ts文件 2、导入要到处的组件&#xff0c;使用vue提供的install 功能全局挂在&#xff1b; import GWButton from "/views/GWButton.vue"; import GWAbout from "/views/AboutView.vue";const components {GWButton,GWAbout, …

canvas路径剪裁clip(图文示例)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

python执行linux系统命令的三种方式

前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 1. 使用os.system 无法获取命令执行后的返回信息 import osos.system(ls)2. 使用os.popen 能够获取命令执行后的返回信息 impor…

什么是SDN-软件定义网络

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle O…

力扣之2648.生成 斐波那契数列(yield)

/*** return {Generator<number>}*/ var fibGenerator function*() {let a 0,b 1;yield 0; // 返回 0&#xff0c;并暂停执行yield 1; // 返回 1&#xff0c;并暂停执行while(true) {yield a b; // 返回 a b&#xff0c;并暂停执行[a, b] [b, a b]; // 更新 a 和 …

大力说视频号第五课:千粉才能直播带货?如何做到

腾讯对直播带货设置了条件&#xff1a;要么你的账号得有1000个粉丝&#xff0c;要么你得开通视频号小店。 对于那些还没有开通视频号小店的用户&#xff0c;他们要想申请直播带货&#xff0c;就必须完成微信实名认证、拥有1000个以上的有效关注者&#xff0c;并缴纳一笔保证金。…