C语言中字符串的使用与进阶

发布时间:2023年12月25日

//这篇文章基本上包括了c语言(上)中有关于字符串的知识点,也是我自己用来复习字符串的资料

一、字符串的基本介绍

1、字符串能同时保存多个文字符号的容器型数据类型,里面的每一个符号都是字符串中的一个元素

2、字符串有序且不可改变

3、字符串引号中的每一个独立的符号都是字符串的元素,这些符号又叫做字符

4、 任何文字符号都可以是字符串的元素(包括英文符号、中文符号、阿拉伯数字、表情符号、韩语、日语…)

5、空串: 引号中没有任何符号的字符串(引号中有空格的时候不是空串) 字符串里面啥也没有,长度为0。

二、在c++中间有关于字符串的知识

在一开始的c语言中间没有字符串的表示形式,于是c++有了两种不同类型的字符串表示方法

1、c风格字符串(在c语言中同样也通用的)

一、字符串的定义

1、C语言没有提供字符串类型,而是使用元素类型为char的数组代替,具体而言,字符串一般用一维字符数组来存放,还可以用二维字符数组可以存放多个字符串。

2、字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。(因而会默认在字符串的最后加上一个\0,使得最后产生长度为3的字符串实际上需要4长度的数组)

3、定义一个数组,使得数组里面的元素就是字符串

格式1:char (数组名字)[n]={'a','b','c','d','\0'}//本质上是对于数组定义的空间不断地放入一个个字符;

n为数组的长度,因为数组最后一个要保留一个\0,于是数组的长度要比你的字符的长度多1。这个中括号中间是可以什么都不填,空在那里了话会自动选择合适长度的数组大小

数组元素存放的是字符,因此用单引号而不是用双引号(使用双引号之后,数组里面的字符就变成了字符串了)

格式2:char (数组名称)[]="abcd"

注意,此时我们这里是使用的是双引号,于是我们是直接输入了这个字符串,而不是像第一种一样往里面输入的是字符,于是我们要用双引号而不是单引号。 例程:

#include <iostream>
using namespace std;
int main ()
{
 ? char greeting[] = {'H', 'e', 'l', 'l', 'o', '\0'};
 ? cout << greeting << endl;
 ? return 0;
}

4、我们使用char数组进行定义,直接把字符串放在了一个字符数组中;而如果先要定义一个数组,之后再对其进行赋值,就要对于原来数组的每一个元素都进行赋值

sC[0]= 'h',sC[1]= 'e',sC[2]= 'l',sC[3]= 'l',sC[4]= 'o',sC[5]= '\0';

5、字符串只有在定义的时候可以一次性对于所有的元素进行定义,一旦定义完成之后就只能一个个的赋值了。

char str[]='abc';//使用这样的操作是可行的

char str[4];

str='abc';//但是像没有在定义的时候进行赋值则就会导致对其的赋值失败。

限制:一些用于操作C风格字符串的标准库函数定义在string头文件这个头文件比较少见,于是这种方法的实用性不强中,是C语言头文件string.h的C++版本

二、字符串中的一些特殊函数
1、字符串连接函数

基本格式:strcat(N1,N2);

先定义N1、N2、函数的作用是N2的字符串连接在N1的后面,并且最后的字符串的名字是N1

例程:

#include <iostream>
?
//#include <string.h>
?
#include <cstring>
?
using namespace std;
?
int main ()
?
{
?
 ? char str1[]="李小明";
?
 ? char str2[]="是大学生";
?
 ?
?
 ? //cout << strcat(str1,str2)<< endl;  //本句和下面两句效果相同
?
 ? strcat(str1,str2);
?
 ? cout <<str1<< endl;
?
 ? return 0;
?
}

2、字符串复制函数(把其中一个字符串中间的字符复制到另外一个函数)

基本格式:strcpy(new,old);

注意:新的是在前面!!!老的才是在后面的!!

#include<iostream>
//#include<string.h>
#include<cstring>
using namespace std;
int main() 
{
    char str1[]="zzh";
    char str2[20] ;(留有足够的样本空间,这是常识了吧)
    strcpy(str2,str1);
    cout<<str2<<endl;
    return 0; 
}

3、字符串比较函数

格式:strcmp(N1,N2);

从第一个字符开始,不断比较它们的ASCII码,N1大就输出正数,N2大就输出负数,一样为0

4、字符串比较函数

格式:strlen(N1)

给出不包含结束符的长度

2、c风格中的二维数组

基本概念:二位数组中的每一个元素都是字符串,即二位数组是字符串的数组。

e.g. char ss[3] [10];

说明建立的这个ss二维数组里面,可以储存3个字符串,每个字符串的长度不超过9

其中:ss[0]表示第一个字符串,其后以此类推。(在通过循环来输入字符串的时候不要忘记了!)

3、c++中的string类型

头文件要有<string>!!!

一、定义string的方法

string s1;(没有初始化,会把默认值赋给s1,即“”)

string s2=“c ++”(在定义的同时初始化为C++,不同的是string的结尾没有\0)

string s3=s2;(定义s3与s2一致)

二、有关的函数

1、求解字符的长度

对于定义好的字符串s1:

len=s1.length();(即是把s1的长度赋值给len,因为是整数,于是可以使用int)//len这个字符可以提前进行取整

特征:输出的字符串长度是字符串的原始长度,不像使用c风格会导致字符串的长度会自动加一

2、对于字符串中的某一个元素进行替换

s1[3]="a";指的是对于第4位进行改变,改变为a;注意,在所有的字符串中,第一个字符都是第0位,所以在选择对于字符串中的某一位进行更改的时候需要小心

3、优点:把字符串作为运算符而不是数组,因此可以方便地对字符串进行拼接。

用char数组定义的字符串可以直接与用string定义的字符串进行组合

4、字符串的增删
增加:

s1.insert(5,s2);

//s1要进行增添的字符串;

//5:插入新字符串的位置:在第五位的后面增添字符串

//s2:加入的字符串

删减:

s1.erase(8);

//删除第8位之后所有的字符

提取:

s2=s1.substr(4,3);

//提取第四位之后字符串的三位到新的字符串s2

5、字符串的查找(字符串中间是不是有特定的字符串)

int a=s1.find(s2,n)

//在s1中寻找s2,并且把s2所在的位置用a进行储存(s2在哪一位的后面并且空格也占用一位i的字符串)

字符串指针

解释:使用一个指针指向字符串

方法一:

char str[]="emmm";

char *pstr=str;

//特点:字符储存在全局数据区,于是对于字符串有读取和写入 的权限;

方法二:

char *str;

str="emmm"

or: char* str="emmm"

//特点:字符储存在常量区,于是字符串只有读取的权限,没有写入的权限,字符串定义之后就无法修改,对于字符串的赋值都是错误的;

//原理:系统再内存中开辟了一个无名的字符数组来存放这个字符串变量,但是在这个字符数组是没有名字的,于是能通过数组名字来进行引用,只能通过指针变量来进行引用。从而导致无法对于字符串进行更改;

因为对于字符数组而言:归根结底它仍然只是一个数组于是在对于字符串进行处理的时候同时可以用下面的方式表现输出的字符串

一下这四种表示方法都是正确的

  • *(pstr+i)

  • pstr[i]

  • *(str+i)

  • str[i]

对于字符串指针重要的结论:
  1. 在对于字符串指针进行定义的时候,系统自动为所有的字符串末尾加上一个 "\0 ";

  2. 字符串指针指针指向的地址是字符串首字符的地址,但是我们对于字符串进行输出的时候,系统会输出str所指的第一个字符,之后自动是str+1,使之不断指向下一个字符,直到最后遇到了'\0'为止。

  3. 对于数值型数组进行输出:printf("%d",a);是不行的,我们知道储存在指针里面的是一个地址,直接对于指针进行输出的结果就只是一个地址的位置;

  4. pstr++就是对于*pstr所指向的数组的下一位

字符串指针作为函数的参数

目的:在被调用的函数中改变字符串的内容,在原函数中会有相应的变化(这样的函数是不用返回值的,因为本质上就是对于指针指向的字符串进行处理)

一、原始的形式:使用数组进行传输
`char a[]="emmm";`
?
`char b[]="oioi";`
?
`boom(a,b);`
?
`viod boom(char from[],char to[]);`

对于数组进行处理最简单的处理形式,就是单纯的把数组输入到这个函数中,请记得在使用函数的时候,不用加上后面的[];但是在后面使用新函数的时候你引入的自变量是一个数组,于是你要把对应的数组c形式作为你函数的自变量。

二、使用指针的形式进行书写
`char a[]="emmm";`
?
`char b[]="oioi";`
?
`char *pa=a;`
?
`char *pb=b;`
?
`boom(pa,pb);`
?
`viod boom(char from[],char to[]);`

一般的字符串指针的形式,和原来的直接使用数组会比较相像,但使用pa往往可以简化后面的计算

三、使用字符指针为变量的装b形式
char *a="emmm";
?
char *b="oioi";
?
boom(a,b);
?
viod boom(char *from,char *to)

虽然boom函数处理的是指针变量,但是这个指针变量在编译系统中还是对于指针变量对应的数组进行处理。但是从表面上来看,调用到函数中的是两个指针,于是在函数的自变量的地方要定义他们是对于指针进行处理。

使用字符串指针的优越性

可以对于很多比较复杂的编程过程进行简化的表达

void copy_string(char* from, char* to)//一个很简单的复制函数
{
    for(;*from!='\0';from++,to++)
 ?  {
        *to=*from;//对于每一位上面的字符进行赋值的操作
 ?  }
    *to='\0';//就是在最后一位加上\0来保证最后的字符串是完成的
}

其中比较亮眼的就是from++和to++;

主要的依据是因为字符串指针申请的是一个连续的空间,而from代表的是首地址的值。于是正好使用指针可以起到最后指向下一位的结果,达到最后不断读取下一位的结果; 注意区别下面几类有关于对于字符串进行直接操作的函数

  • `*p++:指的是*(p++);

  • (*p)++:把*p对应的那一个数值加上1;

  • *(p++):先对于*p进行取值,之后将p指向下一个位置

int arr[] = {1, 2, 3};
int *p = arr; // p指向数组arr的第一个元素
?
int a = *(p++); // 先取出p指向的值1,然后将p指向下一个位置
printf("%d\n", a); // 输出:1
?
printf("%d\n", *p); // 输出:2,因为p已经指向了下一个位置

例子如上图所示

{
    while (*from!='\0')
    {
        *to++ = *from++;
    }
    *to != '\0';
}

因而上面的程序可以改写成这样的形式:

执行的过程是先将*from赋值给*to,之后使得to和from都增量并且指向下一个位置

字符指针与数组之间的关系

字符指针与数组之间是有区别的,绝对不可以一概而谈

  1. 字符数组由若干个元素组成,每一个元素中放一个字符;而字符指针存放的是一个地址(首个字符在内存中的地址)

  2. 初始化:数组可以在定义的时候对于各个元素进行赋值,但是不能使用赋值的语句对于数组的所有元素进行整体赋值;

    char str[14];
    str[] = "1 love China!";    //把字符串赋给数组中的各元素,错误

  3. 存储空间:在编译的时候会给分配与其申请的时候相同的空间;而对于字符指针变量本身是分配四个字节;(为其划分出来的储存字符串的空间在其有具体指向某一字符串的时候会划给他)

  4. 指针变量的值是可以改变的,会变化他的指向;

  5. 数组中各元素的值在运算的过程中可以随便改变的,但是被字符数组定义的字符串中间的内容不能再一次被赋值的。

  6. 在对于字符串中间的某一个元素进行引用的时候,使用字符指针和数组都可以使用下标和地址两种方式对于元素进行引用。

本文文章参考:

《C语言程序设计》(第四版)

本篇文章会持续更新捉虫,各位大佬如果发现哪里有问题了话可以在评论区讨论讨论,有不会的地方我也会尽力去解答。?

文章来源:https://blog.csdn.net/2301_79503048/article/details/135188117
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。