C语言 字符串
声明方式:
// 1. 类型一:字节数组定义字符串
char str[4] = "abc"; // 手动指定长度
char str2[] = "1234"; // 根据内容自动定义长度
//2.类型二:通过指针声明
char* zStr1 = "1234";
字节数组声明字符串细节
NaN. 存储的字节数组。
NaN. 在底层,存储的时候,C语言还是帮我们转换成字节数组进行保存,并且在末尾加上 \0
做结束符号:char str[2] = "a" 其实是 {'a' , '\0'}
NaN. 数组的长度要么不写,如果写的需要预留结束符号的位置
NaN. 字节数组 + 双引号定义字符串,字符串内容是可以改变的 【可读、可写的】
指针声明声明字符串细节
NaN. 变量中存储的内存地址值
NaN. 在底层,存储的时候,C语言还是帮我们转换成字节数组进行保存,并且在末尾加上 \0
做结束符号:char str[2] = "a" 其实是 {'a' , '\0'}
NaN. 指针声明的支付串,会将字符数组放入只读常量区中。
NaN. 只读常量区的特点:
- 只读常量区中的数据是不可以修改的
- 只读常量区定义好的数据是可以复用的,如果需要声明一个只读常量区的数据,创建内存空间之前,会检测常量区是是否存在该数据了,如果存在了就直接返回该数据对应的地址值,如果没有才会创建内存空间。
- 修改就会出现段错误:``Segmentation fault (core dumped)``
变量字符串
#include <stdio.h>
int main() {
char str[100] = "";
printf("输入字符串:");
scanf("%s", str); // 引用数据类型变量中存储的就是指针,所以在 scanf 的参数就无需在变量前面加上 & 符号
printf("%s \n", str);
//for (int i = 0; i < 100; i++)
//{
// if (str[i] == '\0') {
// break;
// }
// printf("%c \n", str[i]);
//}
char* c = str;
while (1) {
char t = *c;
if (t == '\0') {
break;
}
printf("%c \n", t);
c++;
}
return 0;
}
字符串常用方法
#include <stdio.h>
#include <string.h>
int main() {
// string 方法
char* str1 = "abc";
char str2[100] = "Abc";
char str3[5] = { 'q','w','e','r','\0' };
printf("---------获取字符串长度 strlen --------\n");
//printf("str1=%zd \n", strlen(str1));
//printf("str2=%zd \n", strlen(str2));
//printf("str3=%zd \n", strlen(str3));
// 细节:获取长度 = 看的字符长度 - 1 【不包括结束标记符 \0 】 ;
printf("---------字符串拼接 strcat --------\n");
/*strcat(str2, str3);
printf("%s \n", str2);
printf("%s \n", str3);*/
// 结果:将后一个参数的字符内容拼接到前一个字符中
// 细节:
// 1. 前一个参数的字符要是可写的字符串才行
// 2. 前一个参数要有足够空间可以容纳后一个字符串的全部内容才能拼接成功 需要的空间 >= 原来的空间 + 拼接的空间
printf("---------字符串拷贝 strcpy --------\n");
/*strcpy(str2, str3);
printf("%s \n", str2);
printf("%s \n", str3);*/
// 结果:将后一个参数的所有内容拷贝的前一个参数中,这里的拷贝是覆盖原来的内容
// 细节:
// 1. 前一个参数的字符要是 可写的字符串才行
// 2. 前一个参数要有足够空间可以容纳后一个字符串的全部内容才能拷贝成功 需要的空间 >= 拷贝的空间
printf("---------比较字符串 strcmp --------\n");
//int res = strcmp(str1, str3);
//printf("%d \n", res);
// 结果:得到一个 0 或者非零的结果: 如果是 0 就代表两个字符串一模一样 【内容和字符位置都是一样的】
printf("--------- 字符串转小写 strlwr --------\n");
//_strlwr(str2);
//printf("%s \n", str2);
// 细节:strlwr 转换的字符串必须是可写的 , 只能转换英文字符
printf("--------- 字符串转大写 strupr --------\n");
_strupr(str2);
printf("%s \n", str2);
return 0;
}
拓展
清理输入缓冲区
在循环使用 scanf
函数接收的输入的数据,当输入的错误的,并且在循环中输出了其他内容,会导致死循环。
解决方法: 利用 while + getchar 将所有错误数据接收起来,但是不做任何处理,就是实现了,清除所有错误输入的效果。
// 清除输入缓冲区中的错误输入 , 清理所有的错误输入 ,
while ( getchar() != '\n' ) {
;
}
自定义字符串拼接
#include <stdio.h>
#include <string.h>
void forArr(char* arr, int len) {
for ( int i = 0; i < len; i++ ) {
printf("%c ", arr[i]);
}
printf("\n");
}
/// @brief 字符串拼接
/// @param str1
/// @param str2
/// @return 字符串
/**
strlen + 指针
*/
void strJoin(char* str1, char* str2, char* str3) {
int len1 = strlen(str1); // 6
int len2 = strlen(str2); // 6
int len3 = len1 + len2;
// TODO bug 无法接受 str2 的值
for ( int i = 0; i < len3; i++ ) { // 0 - 6
*(str3)++ = i < len1 ? *(str1++) : *(str2++);
}
}
/**
利用指针
*/
void strJoin2(char* str1, char* str2, char* str3) {
while ( *str1 != '\0' ) {
*str3 = *str1;
str3++;
str1++;
}
while ( *str2 != '\0' ) {
*str3 = *str2;
str3++;
str2++;
}
}
int main(int argc, const char* argv[]) {
char* str1 = "123456";
char* str2 = "abcdef";
char* str3;
// strJoin(str1, str2, str3);
strJoin2(str1, str2, str3);
printf("%s\n", str3);
return 0;
}
注意点:
- 不要考虑使用函数返回的数据,因为这里需要返回指针,如果直接返回指针,指针会随着函数的执行完毕后消失。
- 指针++ ,去到一个存储数据的位置。
编写一个程序,清除用户输入字符串中的空格符并将之输出。(例如用户输入”a b”,输出”ab”)
#include <stdio.h>
#include <ctype.h>
int main(int argc, const char* argv[]) {
int count = 0;
char str[100];
char* ptr = str; // 初始化指针,要不然容易出问题
char c;
while ( (c = getchar()) != '\n' ) {
if ( !isspace(c) ) {
*(ptr++) = c;
count++;
}
}
// 添加字符串的结束标记 ,不然会出现乱码;
str[count] = '\0';
printf("%s \n", str);
return 0;
}
注意:
- 指针记得要初始化,要不然容易出错
- 如果是将一些字符存入字符数据中,记得在最后添加一个结束标识 `\0`;
License:
CC BY 4.0