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

C/C++字符串

文章目录

  • 前言
  • 一、字符串简介
  • 二、字符串定义形式
    • 1、以字符数组形式定义
    • 2、以char*形式定义
    • 3、以const char*形式定义
    • 4、以string形式
  • 三、地址输出
  • 四、sizeof和strlen比较
  • references


前言

本文用于记录C/C++中字符串的相关知识

一、字符串简介

字符型变量(char)用于存储一个单一字符,其中每个字符变量都会占用 1 个字节。在给字符型变量赋值时,需要用一对英文半角格式的单引号(’ ‘)把字符括起来。字符变量实际上并不是把该字符本身放到变量的内存单元中去,而是将该字符对应的 ASCII 编码放到变量的存储单元中。char的本质就是一个1字节大小的整型。
**字符串是内存中一段连续的char空间,以’\0’(数字0)结尾。**字符串常量是由双引号括起来的字符序列,如“china”、“C program”,“$12.5”等都是合法的字符串常量。

字符串常量与字符常量的不同
每个字符串的结尾,编译器会自动的添加一个结束标志位’\0’,即 “a” 包含两个字符’a’和’\0’。
在这里插入图片描述

二、字符串定义形式

1、以字符数组形式定义

字符串一定是一个char型数组,但char型数组未必是字符串

 char str1[] = {'h', 'e', 'l', 'l', 'o'};
 printf("%s\n", str1); // 普通字符数组,一般输出为乱码
 char str2[] =  {'h', 'e', 'l', 'l', 'o', 0};
 char str3[] =  {'h', 'e', 'l', 'l', 'o', '\0'};
 printf("%s\n", str2); // hello
 printf("%s\n", str3); // hello

测试数组的大小和字符串的长度

char str4[] = "hello world";
char str5[100] = "hello world";
char str6[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0};
char str7[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'};
printf("str4=%d\n", strlen(str4)); //11
printf("str5=%d\n", strlen(str5)); //11
printf("str6=%d\n", strlen(str6)); //11
printf("str7=%d\n", strlen(str7)); //11
printf("str8=%d\n", strlen(str8)); //11
printf("str4=%d\n", sizeof(str4)); //12
printf("str5=%d\n", sizeof(str5)); //100
printf("str6=%d\n", sizeof(str6)); //12
printf("str7=%d\n", sizeof(str7)); //12
printf("str8=%d\n", sizeof(str8)); //100

首先需要注意的是sizeof是关键字不是函数,不需要包含任何头文件,而且strlen和sizeof返回类型是size_t,格式化输出%d会产生如下警告:
在这里插入图片描述
言归正传,从输出结果可以看出,strlen函数不会计算最后的结束标志符’\0’,无论是人为添加的(如str6\str7)或编译器添加的(如str4),str5、str8是一个长度为100的字符型数组,其未初始化位置默认初始化为0。
注意:定义字符数组一定要进行初始化!
看下面这个例子:

  • 未初始化

    void test01()
    {
        char test[40];
        for(int i=0; i<26; ++i)
        {
            test[i] = 'A' + i;
        }
        for(int i=0; i<26; ++i)
        {
            printf("%c ", test[i]);
        }// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
        printf("\n");
        printf("%d\n", sizeof(test)); // 40
        printf("%d\n", strlen(test)); // 29
    }
    
  • 初始化

    void test02()
    {
        char test[40] = {0};
        for(int i=0; i<26; ++i)
        {
            test[i] = 'A' + i;
        }
        for(int i=0; i<26; ++i)
        {
            printf("%c ", test[i]);
        }// A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
        printf("\n");
        printf("%d\n", sizeof(test)); // 40
        printf("%d\n", strlen(test)); // 26
    }
    

从输出结果可以看出,未初始化的字符数组strlen后的结果不对,这是因为当我们对test字符串进行时,申请到一块内存,此时这块内存中可能储存有值,导致使用strlen计算test字符串时找不到字符串结束标志 ’\0‘(strlen不计算\0的结果),而会在test申请的那片内存后面一直找下去,找到 ’\0‘ 后输出,计算的结果,此时输出的结果肯定错误的结果。

2、以char*形式定义

char*本质上是一个常量指针。

char *s1 = "hello";
//s1[0] = 'H'; erro
s1 = "world";
printf("%s\n",s1); // world

char*是一个常量指针(常量的指针),即它指向的内存中的内容不能发生改变,但它可以改变自身的指向。

 char s2[] = "java";
 char *s3 = "python";
 s3 = s2;

注意:char*形式定义字符串具有风险

char *p = "hello";
  1. 在栈区开辟内存放char* p。
  2. 在常量存储区开辟内存放"hello"。
  3. 将"hello"中第一个字符的内存地址赋值给p。

其中,"hello"是不允许修改的。当你试图去修改内存中的常量区,肯定会报错!

3、以const char*形式定义

const char* 是一个常量指针,表示指针的指向可以修改,指针的值无法修改。

const char* s1 = "hello";
printf("%s\n", s1);
char s2[] = "world";
s2[0] = 'W';
s1 = s2;
printf("%s\n", s1);
//s1[0] = 'w'; error 表达式必须是可修改的左值

相较于char * 形式,const char * 的形式更加直接明了,建议使用这种形式。

4、以string形式

区别stringchar*
本质STL中的一个容器,封装了char *常量指针
内存管理由系统进行管理,无需手动处理堆/栈,如果是堆需要手动进行释放
  • string 和 const char*互转

    //string转const char*
    #include <string>
    string s = "sss";
    const char* c = s.c_str();
     
    //const char*转string
    const char* c = "ppp";
    string s = c;
    
  • string 和 char *互转

    //string转char*
    #include <string>
    string str = "string";
    //法一
    char* chr = const_cast<char*>(str.c_str());
    //法二
    char *cstr = &str[0];
     
     
    //char*转string
    char* c = "ppp";
    string s = c;
    
    

三、地址输出

  • printf

    char s1[] = "hello";
    char *s2 = "hello";
    const char *s3 = "hello";
    char s4[10] = {'h', 'e', 'l', 'l', 'o'};
    printf("%p\n", s1); // 0x16d3ab1a0
    printf("%p\n", s2); // 0x102a57fa2
    printf("%p\n", s3); // 0x102a57fa2
    printf("%p\n", s4); // 0x16d3ab1a8
    
  • cout

    char s1[] = "hello";
    char *s2 = "hello";
    const char *s3 = "hello";
    char s4[10] = {'h', 'e', 'l', 'l', 'o'};
    string s5 = "hello";
    cout << &s1 << endl; //0x16b08b1b0
    cout << &s2 << endl; //0x16b08b1a8
    cout << &s3 << endl; //0x16b08b1a0
    cout << &s4 << endl; //0x16b08b1b8
    cout << &s5 << endl; //0x16b1ff188
    

四、sizeof和strlen比较

sizeofstrlen
性质运算符函数
头文件string.h
功能以字节为单位计算操作数占用的内存大小计算字符串的长度 (strlen函数遇到\0就会停止下来,返回\0前出现的字符个数,不包括\0)
时间编译时运行时
返回值size_tsize_t
参数基本类型/自定义类型const char*\char*\char[]

references

C、C++ 对于char*和char[]的理解
char * 和const char *的区别

相关文章:

  • 基于Python GDAL库实现图像的几何校正详细教程
  • SpringBoot接参注解与校验失败后的三种异常
  • 【C语言学习】变量和数据类型
  • 【Vue2从入门到精通】详解Vue.js的15种常用指令及其使用场景
  • SpringMVC(8)——SSM整合
  • 【内网安全】横向移动Exchange服务有账户CVE漏洞无账户口令爆破
  • 10、Django开发总结:Django缓存Cache应用场景、设置以及高级使用技巧
  • 【黑客技术】LOIC —— 低轨道离子炮工具使用
  • 华为OD机试用java实现 -【吃火锅】
  • C语言 —— 数组
  • 35岁大龄程序员职业转型规划
  • IntelliJ IDEA 2023.1 最新变化
  • Qt音视频开发22-音频播放QAudioOutput
  • 递归--【天梯L2】愿天下有情人都是失散多年的兄妹
  • 第七章 react组件实例中三大属性之props
  • 《Java8实战》-第四章读书笔记(引入流Stream)
  • 【node学习】协程
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Akka系列(七):Actor持久化之Akka persistence
  • Docker入门(二) - Dockerfile
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • Mysql数据库的条件查询语句
  • Node + FFmpeg 实现Canvas动画导出视频
  • Odoo domain写法及运用
  • spring security oauth2 password授权模式
  • vue-loader 源码解析系列之 selector
  • 彻底搞懂浏览器Event-loop
  • 大数据与云计算学习:数据分析(二)
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 我从编程教室毕业
  • 回归生活:清理微信公众号
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (实战篇)如何缓存数据
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • ***监测系统的构建(chkrootkit )
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .htaccess配置常用技巧
  • .NET NPOI导出Excel详解
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • [AR]Vumark(下一代条形码)
  • [C# 基础知识系列]专题十六:Linq介绍
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • [Git 1]基本操作与协同开发
  • [hdu 2826] The troubles of lmy [简单计算几何 - 相似]
  • [JavaWeb学习] tomcat简介、安装及项目部署
  • [LeetCode 127] - 单词梯(Word Ladder)
  • [LeetCode]—Simplify Path 简化路径表达式
  • [poj] 3422 Kaka's Matrix Travels || 最小费用最大流