C语言(十)字符、字符串操作

单字符输入输出

putchar(int c)函数:向标准输出写一个字符,但是输入是int类型,返回类型也是int 表示写了几个字符,一般为1,EOF(即:值-1)表示失败。(end of fail)
getchar():从标准输入读入一个字符,返回类型也是int(因为要返回EOF表示输入结束了)
写一个程序进一步理解。

int ch;
while((ch=getchar())!=EOF){
	putchar(ch);
}
printf("EOF\n");//这样来看读入什么会EOF
return 0;

不管怎么输入数字串、字符串都不停止,直到输入Ctrl-C,程序直接结束但没有看到EOF,这表示我们将程序强制结束了而不是正确的输入EOF。
第二次尝试输入Ctrl-D,得到输出EOF(Windows要输入Ctrl-Z)。而且另一件奇怪的事情是,即便输入12435435数字串,敲下回车之前都不会有回应,敲下回车后才原封不动地输出这一串。为什么?getchar()不是一个个读的吗?
原因:之前提到过中介shell,shell先处理输入的东西再给程序,输出的东西也先经过处理再呈现给我们。(当时在讲\b会变成什么样子)
用户(键盘等输入)→shell→程序
用户←shell←程序
shell对输入的东西做了行编辑,也就是敲下回车前输入的部分都在shell里处理,放在缓冲区里,按下回车后才送到程序那里。如:输入123,shell缓冲区里为“1,2,3,回车”。然后getchar()再读缓冲区。
如果按下Ctrl-D,shell会生成一个EOF的标志。而按下Ctrl-C,shell直接关闭了程序。
所以用户的输入是让shell填写缓冲区,而scanf()和getchar()都是在缓冲区内读。

字符串函数strlen

string.h头文件中处理字符串的函数比如:strlenstrcmpstrcpystrcatstrchrstrstr
strlen(const char*s):返回s的字符串长度(不包括结尾0)由参数表中的const可知该函数不会修改传入的数组。

char line[]="Hello";
printf("%lu\n%lu",strlen(line),sizeof(line));

输出结果:strlen=5,sizeof=6(结尾的0)
我们能不能写出一个strlen函数呢?
sizeof不行,因为我们得到的是指针所占据的大小。
我们需要遍历数组:H,e,l,l,o,\0
因为不知道数组有多大,用while循环。

int cnt=0;
while(s[cnt]!='\0'){
	cnt++;
}
return cnt;

字符串数组strcmp

int strcmp(const char*s1,const char*s2):比较两个字符串。

返回值意义
0相等
1s1大
-1s2大
大小是怎么定义的?
我们做一个尝试:
printf("%d\n",s1==s2);来判断s1和s2是否相等。
然而即便s1和s2内容相同还是输出了0.因为实际上s1==s2比较的是s1和s2的地址,所以数组之间的这种比较永远是0。
s1[]="abc";
s2[]="bbc";

再用strcmp比较两者输出了-1.这很合理,因为ASCII码b>a.

s1[]="abc";
s2[]="Abc";

输出32?32是'a'-'A'的结果。所以这回给出的结果是不相等的字符的差值。

s1[]="abc";
s2[]="abc ";//多了个空格

输出-32,是空格位\0-' '造成的。
接下来我们自己尝试写strcmp。我们需要下标idx,s1[idx]与s2[idx]比较,当s1[idx]和s2[idx]都=='\0’时停止(假设长度相等)。

while(s1[idx]!='\0'&&s1[idx]==s2[idx])//当出现不相等的字符或者字符串到了末尾时,返回差值
	idx++;
return s1[idx]-s2[idx];

改进:idx可不可以不用?
用指针:

*s1==*s2
s1++;
s2++;
return *s1-*s2;

这是处理字符串的两种手段,数组和指针。看个人喜好。

字符串函数strcpy

char*strcpy(char* restrict dst,char* restrict src);
把src拷贝到dst的空间里,包括结尾的\0.
restrict表示src和dst不能重叠。比如src是
H E L L O \0
,dst的内容是:
空 空 空 H E L L O \0
也就是说想把HELLO挪到第一位开始,这是不行的。因为strcpy对于多核计算机,为了提高效率,拷贝可能是交给不同的核不同的段,分别拷贝。
函数参数中的第一个参数是目的,而第二个参数是源。而且这个函数是有返回值的,返回dst

char *dst=(char*)malloc(strlen(src)+1);//不包含结尾的\0,所以+1
strcpy (dst,src);

+1是重点。
接下来尝试自己写strcpy()函数。

char *mycpy(char*dst,const char*src)
{
	int idx=0;
	while(src[idx]!='\0')
	{
		dst[idx]=src[idx];
		idx++;
	}
	dst[idx+1]='\0';
	return dst;

指针的做法是:

char *ret=dst;
while(*src!='\0')
{
	*dst=*src;
	*dst++;
	*src++;
}
*dst='\0';
return ret;

当然do-while也行.
也可以这样优化:

while(*src)*dst++ = *src++;

更艹的是,*dst++ = *src++;的结果就是*src,所以我们可以直接写

while(*dst++ = *src++);

字符串函数strcat

char*strcat(char* restrict s1,const char* restrict s2);
把s2拷贝到s1后面,接成一个长字符串;返回s1.(s1结尾的\0被s2开头替换掉)
如:s1: H E L L O \0
s2:W O R L D\0
结果:s1: H E L L O W O R L D \0
s1必须要有足够的空间。
cpy和cat有可能没有足够的空间,因此这两个函数是不够安全的,不建议使用。
安全版本:strncpystrncat

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

会拷贝能拷贝的最多的字符,多的部分掐掉。而strncmp则是只判断前几个字符。

字符串搜索函数

char* strchr(const char* s,int c);
char* strrchr(const char* s,int c);//从右边开始找
返回的是指针,返回NULL表示没找到。
那如果像HELLO出现两个L,怎样寻找第二个呢?

char *s="hello";
char *p=strchr(s,'l');
printf("%s",p);

输出llo。
想找第二个的方法是:

p=strchr(p+1,'l');

如果想把l后面的东西cpy到另一个字符串中去:

char *t=(char*)malloc(strlen(p)+1);
strcpy(t,p);
free(t);

如果我们想要l前面的部分?

char c=*p;
*p='\0';//把l的位置改成'\0'
char *t=(char*)malloc(strlen(s)+1);
strcpy(t,s);//只拷贝了第一个l前面的部分。

t就是想要的结果,即he
在字符串中找字符串:char* strchr(const char* s1,const char*s2);
不分大小写寻找:char* strcasestr(const char* s1,const char*s2);

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

灰海宽松

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

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

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

打赏作者

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

抵扣说明:

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

余额充值