全面学习C语言【五】:字符串、字符串数组、字符串函数(getchar&putchar、strlen、strcmp、strcpy、strcat、strchr、strstr)

十一、字符串

🎈C语言中的字符串

在C语言中 字符串是这样的:

char msg[]={'H','e','l','l','o','\0'};

在字符数组的末尾有一个\0

在C语言中 字符串是以整数0结尾的一串字符
0和’\0’相同 标志着字符串的结束 但只是作为一个标记的作用 (’\0’代表的是整数0 和’0’是完全不一样的)
但他并不是字符串的一部分 因此在计算字符串长度的时候也不包括这个0
在C语言中 字符串是以字符数组的形式存在的 (这才叫字符"串" 哈哈)
以数组或指针的形式来访问字符串 但更多以指针访问

🚩字符串变量

有好几种方法可以定义字符串变量

char *str="Hello";
char strArr[]="Hello";
char strArr[10]="Hello";

在以字面量的形式定义字符串变量后 编译器会自动在末尾生成一个0标识符

🚩字符串常量

比如 定义了一个字符串"Hello"
这个"Hello"会被编译器转换成一个字符数组放在内存中
这个数组的长度为6 而不是5 因为在末尾还有一个表示字符串结束的0 只是看不见而已

两个相邻的字符串常量会被自动连接(它们中间不能有任何符号)
比如:

printf("你是一个一个一个一个..."
	"啊啊啊啊啊"); // 你是一个一个一个一个...啊啊啊啊啊

当然 也可以使用/来连接 但此时行的连接处不能有引号换行后前面不能有缩进 否则缩进也会被算在字符串内
比如:

printf("你是一个一个一个一个...\
	啊啊啊啊啊"); // 你是一个一个一个一个...        啊啊啊啊啊

这样才对:

printf("你是一个一个一个一个...\
啊啊啊啊啊"); // 你是一个一个一个一个...啊啊啊啊啊

C语言中 字符串是以字符数组的形式存在的 因此 不能用传统的运算符来对字符串进行运算
(Java可以用加号+来连接字符串 但是C语言不可以)
但是可以用字符串形式的字面量来初始化字符数组
比如:

char *str="Hello";

通过数组的方式可以遍历字符串

🎈字符串的创建方式

✨字符串可以使用指针的创建方式:

char* str="Hello";

当创建了两个相同的字符串 它们所指向的位置实际上是同一个地方

char* s1="Hello";
char* s2="Hello";
printf("%p\n",s1); // 00405064
printf("%p\n",s2); // 00405064

在字符串被创建后 实际上该常量是一个指针 指向了内存中的一块代码段区域 字符数组就存放在这
这块区域是只读的 无法写入 因此当写入时候 程序会崩溃
因此 实际上char *str="Hello"是const char *str=“Hello”

✨若要使用可修改的字符串 应该用数组的创建方式char strArr[]="Hello";

char s[]="Hello";
printf("%c\n",s[0]); // H
s[0]='P';
printf("%c\n",s[0]); // P

🎈字符串的创建、赋值、输入输出

创建方式的选择:
  • 若创建为数组 那么字符串的存放位置就在当前位置
    而且作为本地变量 空间是会被自动回收
  • 若创建为指针 那么这个字符串的存放位置不知道在哪
    通常用于作为函数的指针参数 或者用于malloc的动态分配空间
🚩字符串的赋值
char *s1="Hello";
char *s2;
s2=s1;

由于采用的是指针方式创建的字符串 因此实际上在该赋值过程中 并没有产生新的字符串
只是让指针s2指向了指针s1所指的字符串的位置 即 对s2的任何操作 都是对s2做的
s1和s2是共享内存位置

🚩字符串的输入和输出

对于字符串 在C中 使用 %s 来输入和输出 (相信已经猜到了 s就是string)

在读入字符串的时候 到空格 或 tab 或 回车为止
空格 或 tab 或 回车是作为分隔符 因此并不会被算在读入的字符串中

在读入的时候 有可能会遇到数组越界问题 有可能会导致程序崩溃

char word[8];
scanf("%7s",word); // 最多读取7个 剩下留一个位置用于存放最后面的0
printf("%s##",word);

可以用 %ns的格式来 限制最多能读取多少个字符 比如%7s为最多读取7个字符 超过的部分就不读了

因此 若同时读入到多个数组 在到达读取上限后 下个数组会从上次读取上限的地方开始读
比如:

char word1[3];
char word2[3];
scanf("%2s %2s",word1,word2); // 输入123456789
printf("%s\n",word1); // 12
printf("%s",word2); // 34
❗注意

在用指针方式创建数组的时候要进行初始化
不要这么用:

char *s;
scanf("%s",&s);

因为 char*并不是字符串类型 而是指针 当指向的位置无法存入 那么程序就会崩溃
因此 在创建指针的时候 要初始化为0
像这样:

char *s=0;
scanf("%s",&s);

🎈字符串数组

用一个数组来表示很多字符串
可以这么写:

char *arr[];

其意义是 有个数组 其中的每一项存放的都不是确切的值 而是一个指针 该指针指向的位置是所要存放的字符串单元
比如 arr[0]存放的是Hello\0的指针 该指针指向一个位置 这个位置保存着Hello\0这么一个字符串
arr[1]存放的是World\0的指针 该指针指向一个位置 这个位置保存着World\0这么一个字符串
以此类推

例子:

int i;
char *arr[]={"AA","BB","CC","DD","EE"};
for (i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
	printf("%s\n",arr[i]);
}

🎈字符串函数

字符串处理函数放置于string.h中 因此若要使用字符串 则必须先引入#include <string.h>

里面有:

  • strlen
  • strcmp
  • strcpy
  • strcat
  • strchr
  • strstr
🚩getchar & putchar / 读 & 写
【getchar】:

从标准输入读入一个字符

语法:

int getchar(void)

返回值是int 这是因为方便返回EOF(-1)代表输入结束

【putchar】:

向标准输出(即黑窗口)写一个字符

语法:

int putchar(int c)

返回值是 写了几个字符 若返回EOF(-1) 则代表写失败

键盘输入的值是先交给shell 然后shell处理后再交给程序
当未按下回车前 所有输入的值都在shell里
然后一旦按下回车 就会将值存入shell中的缓冲区(回车符也会被存入缓冲区) 程序的getchar从shell的缓冲区中读数据 然后进行处理

因此 当键盘按下Ctrl+V(Unix是Ctrl+D)时 在shell内部会通过一种方式 改变控制程序将要退出的状态码
然后再通过getchar去读取的时候 读到了程序将要退出的状态码 那么便会退出
当键盘按下Ctrl+C 那么直接关闭程序了

int ch;
while((ch=getchar())!=EOF)
{
	putchar(ch);
}

printf("EOF\n");
🚩strlen / 获取长度

strlen:string length
返回传入的字符串的长度

语法:

size_t strlen(const char *s)

例:

char c[]="Hello";
printf("%lu\n",strlen(c)); // 5
printf("%lu",sizeof(c)); // 6 因为后面还有一个\0代表字符串的结束
🚩strcmp / 比较

strcmp:string compare
比较两个字符串 不仅能比较是否相等 还能比较大小

语法:

int strcmp(const char *s1,const char *s2)

返回的是两个字符串之间的差值
因此 若相等 则返回 0

char s1[]="Hello";
char s2[]="Hello";
printf("%d",strcmp(s1,s2)); // 0

后面的若大于前面的 则返回 1
后面的若小于前面的 则返回 -1

char s1[]="abc";
char s2[]="CBc";
printf("%d\n",strcmp(s1,s2)); // 1

当然 该函数还有一个版本 可以限定只比较前面多少位字符

int *strncmp(char *restrict s1,const char *restrict s2,size_t n);
🚩strcpy / 复制

strcpy:string copy
第二个参数的字符串拷贝第一个参数的字符串空间中

语法:

char *strcpy(char *restrict dst,const char *restrict src)
// 参数是(目的,源),而不是(源,目的)

restrict是C99的关键字 意为dst和src不能是重叠的(即字符空间不能有重叠)

返回值是dst 即拷贝后的值(或者可以说是复制品)
其目的是为了能够使用链式编程 使得代码能够串联 返回值再次作为其它函数的参数

复制一个字符串:

char src[]="Hello";
char *dst=(char*)malloc(strlen(src)+1); // 切记要加一 留给最末尾的0
strcpy(dst,src);
printf("%s",dst); // Hello
🚩strcat / 连接

strcat:string concat
将第二个参数的字符串接到第一个参数的字符串后面
返回拼接后的第一个字符串(前提是第一个字符串必须要具有足够的空间)

语法:

char *strcat(char *restrict s1,const char *restrict s2)

其基本实现思路就是将第一个参数最后一位(即结尾符0)替换为第二个参数的字符串的第一位
连接也可以看作是一种拷贝

🚧安全问题

strcpy和strcat都可能产生安全问题
若被拷贝的"目的地"没有足够的空间 那么可能会造成数组越界

解决方法就是使用安全版本:

char *strncpy(char *restrict dst,const char *restrict src,size_t n);
char *strncat(char *restrict s1,const char *restrict s2,size_t n);

安全版本加了个n 其意思为 限制最多能够拷贝/连接多少个字符 若超出限定值 那么会去掉 超出的范围不会被拷贝/连接

🚩str[r]chr / 字符串中查找字符

strchr:string character
strrchr:string rear/right character

搜索函数可以在字符串中查找指定的字符(可以从左找也可以从右找)

语法:

char *strchr(const char *s,int c); // 从左找char *strrchr(const char *s,int c); // 从右找(right)

若返回NULL 则代表未找到
若找到了 则会返回要找的那个字符在该字符串中的指针

char s[]="Hello";
char *p=strchr(s,'e');
printf("%s",p); // ello
🚩str[case]str / 字符串中查找字符串

strstr:string string
strcasestr:string case string

在字符串中查找指定的字符串(可以忽略大小写)

语法:

char *strstr(const char *s1,const char *s2); // 在字符串中查找指定的字符串
char *strcasestr(const char *s1,const char *s2); // 在字符串中忽略大小写查找指定的字符串

若返回NULL 则代表未找到
若找到了 则会返回要找的那个字符在该字符串中的指针

char s1[]="Hello";
char s2[]="ell";
char *p=strstr(s1,s2);
printf("%s",p); // ello

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值