C语言常见问题(五)——字符串

< Back C语言常见问题

目录

一、常见bug:“烫烫烫烫烫烫”

1.解决办法

2.原理

二、字符串定义

1.字符串存储

2.字符串常量

3.字符串变量

三、如何操作字符串

1.字符串变量赋值

2.输入

3.输出

4.计算字符串长度

5.字符串在函数间的传递

6.总结

四、string头文件常用函数

1.计算字符串长度strlen

2.复制字符串strcpy

3.复制前n个字符strncpy

4.字符串比较strcmp

5.比较前n个字符strncpy

6.字符串拼接strcat


一、常见bug:“烫烫烫烫烫烫”

        我想程序员刚开始接触字符串或字符数组时,可能都会遇到“烫烫烫烫烫烫”乱码bug。其实这是由一些不好的编程习惯导致的。例如:

#include<stdio.h>
int main()
{
	char str[20],ch;
	int i=0;
	for(i=0;(ch=getchar())!='\n'&&i<20;i++)
		str[i]=ch;
	printf("%s",str);
	return 0;
}

1.解决办法

解决办法有两个,一个是在字符串结尾加上’\0’,例如: 


另一个是在声明字符数组时初始化

2.原理

为什么这两个方法可行?

        首先这与输出方式有关,你使用了%s格式化输出,说明str存储的应该是一个字符串,而C语言中字符串应该以\0结尾,但你没有。第一种解决办法手动将字符串的下一字符设为’\0’,输出函数遇到\0就停止了,自然不会输出乱码。

        第二种解决办法初始化了栈区中字符数组的存储空间,使其(二进制位)全为0。当你用printf(“%s”,str)输出的时候,输出函数遇到0000 0000(注意\0用二进制表示就是0000 0000)也停止了。

为什么会输出“烫烫烫烫烫烫”?

        “烫”常见于Windows编译环境下。因为vs编译器在分配内存时,对于未赋予初值的栈空间,会使用0xCC填充。因为0xCC已经超出ASCII码的表示范围,编译器会认为这是一个宽字符,从而把两个字节连在一起识别。当两个0xCC连在一起时就形成了0xCCCC,正好对于GBK中“烫”的编码。

我们可以写一段代码验证一下:

 

数组str占10个字节,每个“烫”占两字节,刚好输出5个“烫”

        总结一下,我们在平时写程序的过程中,要养成给变量设置初值的习惯。在涉及字符串的操作时,要注意字符串是否以\0为结尾。

        如果你想对字符串有更全面的了解,可以看看下面的内容。


二、字符串定义

1.字符串存储

        字符串即一串字符,以\0为结尾。\0用十六进制表示就是0x00,用二进制表示就是0000 0000。C程序中字符串有两种存储方式,一种是字符串常量,另一种是字符串变量。

2.字符串常量

        1) 字符串常量存储在常量区,其类型通常为char *。在程序执行期间常量的值不可改变,但可以通过指针获取其值。例如:

#include <stdio.h>
int main() {
    char * str= "Hello World!\n";//常量字符串
    printf("%s",str);
	return 0;
}

        注意虽然我们没有在字符串的结尾加上\0,但是编译器把字符串常量存储到常量区时,会自动将字符串常量之后的二进制位置为0,相当于在字符串的结尾加上\0了。

        2) 此外还有一种实现字符串常量的方式——define,例如: 

#include <stdio.h>
#define STRING "Hello!\n"
int main() {
printf("%s",STRING);
return 0;
}

        注意#define的实质是宏替换,在程序预编译时就对代码进行了替换,其值不会存储在常量区。

3.字符串变量

        C语言没有定义string类型,需要用户自己实现字符串类型。通常我们使用char类型数组来存储字符串变量,并使用\0作为字符串的结尾

//下面是两种给字符串赋初值的方法:
#include <stdio.h>
int main() {
	char str1[10] = "Hello!";	//{"Hello!"}
	char str2[10] = {'H','e','l','l','o','!','\0'};
	printf("str1=%s\nstr2=%s\n",str1,str2);
	return 0;
}

        如果你是用” ”给字符串赋初值,例如char str1[10] = "Hello!",编译器会在字符串结尾自动加上\0。

        如果你是一个字符一个字符地给字符串赋初值,那么你需要手动在字符串结尾加上'\0',例如char str2[10] = {'H','e','l','l','o','!','\0'},否则在以字符串格式输出时就会出错。


三、如何操作字符串

1.字符串变量赋值

        1) 数组声明时赋值

        在给字符串赋初值的时候,可以使用下面两种赋值方式:

        char str1[10] = "Hello!"; //{"Hello!"}

        char str2[10] = {'H','e','l','l','o','!','\0'};

        但是在数组声明语句之外的地方,不能使用上面两种赋值方式,否则编译器会报错(如下图)。主要是因为” ”以及{ }赋值这两种方式都只能在数组定义的时候使用。

        2) 其他情况赋值

可以对字符数组的每个元素逐个赋值,最后以’\0’结尾:

#include <stdio.h>
int main() {
	char str1[10],str2[10];
	//str1赋值:
	str1[0]='H';str1[1]='e';str1[2]='l';str1[3]='l';str1[4]='o';str1[5]='\0';
//str2赋值:
	for(int i=0;i<10;i++)
		str2[i]=str1[i];
	printf("str1=%s\nstr2=%s",str1,str2);
	return 0;
}

也可以使用strcpy函数实现字符串的赋值,记得加上string.h头文件:

#include <stdio.h>
#include <string.h>
int main() {
	char str1[10]="Hello!\n",str2[10]={0};
	strcpy(str2,str1);//将字符串str1赋值给str2
	printf("%s",str2);
	return 0;
}

2.输入

        1) 使用scanf函数

#include <stdio.h>
int main() {
	char str[10];
	scanf("%s",str);
	printf("%s\n",str);
	return 0;
}

 


注意,scanf函数读入字符串遇到空格或回车就停止读入了,因此不能读入空格

        2) 使用gets函数

#include <stdio.h>
int main() {
	char str[10];
	gets(str);
	printf("%s\n",str);
	return 0;
}

注意gets函数遇到回车才停止读入,遇到空格不停止,因此可以读入空格

        3) 逐字符读入

        注意,使用scanf或gets读入字符串,它们会自动在字符串的结尾添加'\0';而用逐字符读入字符串的方式必须在字符串的结尾手动添加'\0'

#include <stdio.h>
int main() {
	char str[20];
	int i=0;
	for(i=0;(str[i]=getchar())!='\n'&&i<20;i++);
	str[i]='\0';//手动添加'\0'
	printf("%s",str);
	return 0;
}

3.输出

        1) printf以%s格式输出

                printf("%s",str);

        2) puts函数

                puts(str);

 注意puts函数会在输出完字符串后自动换行,而printf不会

        3) 逐字符输出

#include<stdio.h>
int main()
{
	char str[20]="Hello World!\n";
	for(int i=0;i<20&&str[i]!='\0';i++)
		printf("%c",str[i]);
}

4.计算字符串长度

#include<stdio.h>
int main()
{
	char str[20]="0123456789!\n";
	int length=0;
	for(length=0;length<20&&str[length]!='\0';length++);//计算字符串str长度
	printf("length=%d",length);
}
//字符串的结束符\0一般不计入字符串长度

5.字符串在函数间的传递

        C语言字符串在函数间的传递通常是以指针形式传递的,即传递数组的首地址(字符数组名),例如:

#include<stdio.h>
#define N 20
int len(char s[]){//计算字符串s的长度
	int length=0;
	for(length=0;length<N&&s[length]!='\0';length++);
	return length;
}
int main()
{
	char str[N]="Hello World!\n";
	printf("%d",len(str));
	return 0;
}

其中函数参数的声明部分下面这几种写法是等价的:
//int len(char s[]);    
//int len(char s[N]);
//int len(char * s);

        注意,因为字符数组是以指针形式传递的,所以如果在子函数中修改了字符串,在返回到主函数时这些修改也会一并保留下来。例如:

#include<stdio.h>
#define N 20
void reverse(char s[N]){//翻转字符串s
	int i=0,j=0;
	char m;
	for(j=0;j<N&&s[j]!='\0';j++);//计算字符串s的长度
	for(j=j-1;i<j;i++,j--){
		m=s[i];
		s[i]=s[j];
		s[j]=m;
	}
	printf("reverse() s:%s\n",s);//翻转后,字符串s的值
	return;
}
int main()
{
	char str[N]="0";
	scanf("%s",str);	//读入字符串str
	reverse(str);		//翻转字符串str
	printf("main() str:%s\n",str);//执行reverse函数后,main函数str的值
	return 0;
}

这里主函数的str和子函数reverse的s是同一个字符数组,它们占用同一个存储空间。 

6.总结

        对字符串的操作,归根结底是对字符数组的操作。因此除了上面提到的方法外,我们可以通过对字符数组各个元素的操作,来实现对字符串更加复杂的操作。在涉及字符串的操作时,我们要注意字符数组是否越界,以及字符串的下一字符是否为\0。


四、string头文件常用函数

        string头文件定义了一些操纵字符串和数组的函数。下面简单讲几个常用的:

1.计算字符串长度strlen

        size_t strlen(char *s);

        求字符串的长度,从字符串的首地址开始到遇到第一个'\0'停止计数,例如:

#include<stdio.h>
#include<string.h>
#define N 30
int main(){
	char str1[N]="There is an apple!";
	printf("%d\n",strlen(str1));
	return 0;
}

2.复制字符串strcpy

        char * strcpy ( char * destination, char * source );

        将字符串source的值复制给destination,例如:

#include<stdio.h>
#include<string.h>
#define N 30
int main(){
	char str1[N]="There is an apple!";
	char str2[N]="0";
	strcpy(str2,str1);//将字符串str1的值复制给str2
	printf("%s\n",str2);
	return 0;
}

 

3.复制前n个字符strncpy

          char * strncpy ( char * destination, char * source, size_t num );

        将字符串source的最多前num个字符复制到字符数组destination中,当num不大于字符串source的长度时,需要初始化destination或在destination字符串结尾追加\0。例如:

#include<stdio.h>
#include<string.h>
int main(){
	char str1[19]="There is an apple!";//数组str1长度为19,其存储的字符串长度为18
	char str2[18]="0";
	strncpy(str2,str1,10);//将字符串str1的前10个字符复制给str2
	printf("%s\n",str2);
	return 0;
}

 


如果num大于字符串source的长度,strncpy会将字符串source的’\0’一起拷贝给destination。

4.字符串比较strcmp

        int strcmp ( char *str1, char *str2);

        比较ASCII码,str1>str2,返回值> 0;两串相等,返回0;str1<str2,返回值<0。例如:

#include<stdio.h>
#include<string.h>
int main(){
	char str1[20]="apple";
	char str2[20]="bpple";
	if(strcmp(str1,str2)>=0)
		printf("str1>=str2\n");
	else
		printf("str1<str2\n");
	return 0;
}

 

5.比较前n个字符strncpy

        char * strncpy ( char *str1, char *str2, size_t num);

        比较str1、str2前num个字符的ASCII码,例如:

#include<stdio.h>
#include<string.h>
int main(){
	char str1[20]="apple b";
	char str2[20]="apple a";
	if(strncmp(str1,str2,5)==0)
		printf("str1==str2\n");
	else
		printf("str1<>str2\n");
	return 0;
}

6.字符串拼接strcat

        char * strcat ( char *destination, char *source);

        将source的内容追加到destination的末尾,例如:

#include<stdio.h>
#include<string.h>
int main(){
	char str1[20]="an ";
	char str2[20]="apple";
	strcat(str1,str2);
	printf("%s\n",str1);
	return 0;
}

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C语言中,可以使用多种方法将数组转化为字符串。以下给出两种常见的方法: 方法1:利用库函数进行转换 ```c #include <stdio.h> #include <string.h> int main() { int i; int array = {5, 2, 0, 1, 3, 1, 4}; char str = "\0"; char str1 = "\0"; for (i = 0; i < 7; i++) { sprintf(str, "%d", array[i]); strcat(str1, str); } printf("%s\n", str1); return 0; } ``` 这种方法利用了sprintf函数将整数转换为字符串,然后使用strcat函数将每个转换后的字符串连接在一起,最终得到一个完整的字符串表示数组。 方法2:利用ASCII方式进行转换 ```c #include <stdio.h> #include <string.h> int main() { int i; int array = {5, 2, 0, 1, 3, 1, 4}; char str1 = "\0"; for (i = 0; i < 7; i++) { str1[i = array[i + '0'; } str1[i = '\0'; // 不可省略 printf("%s\n", str1); return 0; } ``` 这种方法利用了ASCII码将整数转换为对应的字符,然后直接将字符存储到字符串中。需要注意的是,这种方法只适用于处理ASCII码范围内的值。 以上两种方法都可以将C语言数组转化为字符串输出,具体选择哪种方法取决于实际情况和需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C语言中数组转化为字符串的方法](https://blog.csdn.net/weixin_34289744/article/details/90681508)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C语言—— 字符串 和 数组 之间的转换](https://blog.csdn.net/DADWAWFMA/article/details/126790269)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易水卷长空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值