ANSI C中有20多个用于处理字符串的函数:

注意:const 形参使用了const限定符,表示该函数不会改变传入的字符串。因为源字符串是不能更改的。

strlen函数:

函数原型:unsigned int strlen(const char*)

用于统计字符串的长度。举例如下

 void fit(char *,unsigned int);

 int main(void)
{
char mesg [] = "Things should be as simple as possible,""but not simpler."; puts(mesg);
fit(mesg, );
puts(mesg);
puts("Let's look at some more of the string.");
puts(mesg + ); //我们在38位置(空字符\0)后的39位置开始打印缓冲区余下的字符串。 return ;
} void fit(char *string, unsigned int size) //利用strlen函数,设计一个函数可以缩短字符串的长度。
{
if(strlen(string)>size)
string[size] = '\0';
}

strcat()函数:

函数原型:char *strcat(char *strDest, const char *strSrc)

接受两个字符串作为参数,把第2个字符串的备份附加在第1个字符串的末尾。并把拼接后形成的新字符串作为第1个字符串。第2个字符串不变。

 #include <stdio.h>
#include <string.h>
#define SIZE 80 char * s_gets(char * st, int n); int main()
{
char flower[SIZE];
char addon [] = "s smell like old shoes."; puts("What is your favorite flower?");
if(s_gets(flower,SIZE))
{
strcat(flower,addon); //使用了strcat函数进行字符串拼接
puts(flower);
puts(addon);
}
else
puts("End of file encountered!");
puts("bye"); return ;
} char * s_gets(char * st, int n)
{
char * ret_val;
int i=; ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
if(ret_val)
{
while(st[i]!='\n' && st[i]!='\0')
i++;
if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
st[i]='\0';
else
while(getchar() != '\n')
continue;
}
return ret_val;
}

strncat()函数:

strcat()函数有个缺点就是无法检查第1个数组是否能容纳第2个字符串。如果给第1个数组的空间不够大,多出来的字符溢出到相邻存储单元时就会出问题。

函数原型:extern char *strncat(char *dest,char *src,int n);

参数说明:第3个参数指定了最大添加字符数;

这段代码会拼接两个字符,检查第1个数组的大小,重点是确定最大能添加多少字符数;

 #include<stdio.h>
#include<string.h> #define SIZE 30
#define BUGSIZE 13 char * s_gets(char * st,int n); int main(void)
{
char flower[SIZE];
char addon [] = "s smell like old shoes.";
char bug[BUGSIZE];
int available; puts("What is your favorite flower?");
s_gets(flower,SIZE);
if((strlen(addon)+strlen(flower)+)<=SIZE) //important
strcat(flower,addon);
puts(flower);
puts("What is your favorite bug?");
s_gets(bug,BUGSIZE);
available= BUGSIZE -strlen(bug)-;
strncat(bug,addon,available);
puts(bug);
return ;
} char * s_gets(char * st, int n)
{
char * ret_val;
int i=; ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
if(ret_val)
{
while(st[i]!='\n' && st[i]!='\0')
i++;
if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
st[i]='\0';
else //其实是'\0'
while(getchar() != '\n') //会把缓冲区后续的字符都清空
continue;
}
return ret_val;
}

我们发现strcat()也会造成缓冲区溢出。但是它没有像gets()一样被废除。gets()的安全隐患来自使用程序的人。而strcat()的安全隐患来自粗心的程序员。我们无法控制用户会进行什么操作,但是可以控制程序做什么。因此C语言相信程序员。程序员也有责任保证strcat()使用的安全。

缓冲区溢出漏洞:程序员必须保证strcat的第一个参数有足够的空间。编译器无法报错是因为,这个函数的参数是指针类型,函数中也只是通过指针来读写这些内存的。函数根本不知道第一个参数所指的内存空间到底够不够大,函数本身不会对此进行检查。函数的大致行为是找到第一个参数所指的内存中字符串结尾的位置,然后从此处开始写入第二个参数的字符,直到写完。如果向第一个参数写入过多的字符,有可能会引起问题,也有可能不会。这取决于内存空间后面的内存是否可用来读写。万一覆盖了内存空间重要数据,就会引起错误。所以这是严重的安全隐患。

strcmp()函数

函数原型:int strcmp(const char *str1,const char *str2);

strcmp()函数返回的具体值不重要,我们只在意该值是0还是非0;比较两个字符串是否相等;我们关注的是字符串是否相等;

如果真要关心返回值的话,要理解比较的机制:其实是ASCII码值的比较;大写的字母ASCII值比小写的字母小;

比较的是:第一个字符串,相对第二个字符串的大小

str1<str2 返回负值;(ASCII的差值)

str1=str2 等于0;

str1>str2 返回正值;(ASCII的差值)

 //检查程序是否要停止读取输入

 #include <stdio.h>
#include <string.h> #define SIZE 80
#define LIM 10
#define STOP "quit" char * s_gets(char *st, int n); int main(void)
{
char input[LIM][SIZE];
int ct =; printf("Enter up to %d lines(type quit to quit):\n",LIM);
while(ct<LIM && s_gets(input[ct],SIZE)!=NULL && strcmp(input[ct],STOP)!=)
ct++;
printf("%d strings entered\n",ct); return ;
} char * s_gets(char * st, int n)
{
char * ret_val;
int i=; ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
if(ret_val)
{
while(st[i]!='\n' && st[i]!='\0')
i++;
if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
st[i]='\0';
else //其实是'\0'
while(getchar() != '\n') //会把缓冲区后续的字符都清空
continue;
}
return ret_val;
}

strncmp()函数:

函数原型:extern int strcmp(char *str1,char * str2,int n)

参数说明:str1为第一个要比较的字符串,str2为第二个要比较的字符串,n为指定的str1与str2的比较的字符数。

函数功能:比较字符串str1和str2的前n个字符。

返回说明:返回整数值:当str1<str2时,返回值<0; 当str1=str2时,返回值=0; 当str1>str2时,返回值>0。

 //比较前五个字符是否相等
#include <stdio.h>
#include <string.h> #define LISTSIZE 6 int main()
{
const char *list[LISTSIZE]=
{
"astronomy","astounding",
"astrophysics","ostracize",
"asterism","astrophobia"
};
int count =;
int i; for(i=;i<LISTSIZE;i++)
{
if(strncmp(list[i],"astro",)==)
printf("Found:%s\n",list[i]);
count++;
}
printf("The list contained %d words beginning" " with astro.\n",count); return ;
}

strcpy()函数:

函数原型:char *strcpy(char *strDest, const char *strSrc)

这个函数相当于字符串的赋值运算,拷贝字符串;

 #include <stdio.h>
#include <string.h>
#define SIZE 40
#define LIM 5
char * s_gets(char * st, int n); int main(void)
{
char qwords[LIM][SIZE];
char temp[SIZE];
int i = ; printf("Enter %d words beginning with q:\n",LIM);
while(i<LIM && s_gets(temp,SIZE))
{
if(temp[]!='q')
printf("%s doesn't begin with q!\n",temp);
else
{
strcpy(qwords[i],temp);
i++;
}
}
puts("Here are the words accepted:");
for(i=;i<LIM;i++)
{
puts(qwords[i]);
}
return ;
}

声明数组将分配储存数据的空间,声明指针只分配储存一个地址的空间;

使用strcpy函数的时候,程序员有责任保证目标字符串有足够的空间储存源字符串的副本;

strcpy的一些属性:其返回类型是char *,第一,该函数返回的是第1个参数的值,即一个字符的地址;第二,第1个参数不必指向数组的开始。这个属性可用于拷贝数组的一部分。代码如下:

 #include <stdio.h>
#include <string.h>
#define WORDS "beast"
#define SIZE 40 int main(void)
{
const char * orig = WORDS;
char copy[SIZE]= "Be the best that you can be.";
char *ps; puts(orig);
puts(copy);
ps = strcpy(copy+,orig);
puts(copy);
puts(ps); return ;
}

注意:源字符串也会把空字符也拷贝在内。

strncpy()函数:更谨慎的选择

函数原型:char *strncpy(char *dest, char *src, int n);

strcpy()和strcat()都有同样的问题,就是不能检查目标空间能否容纳源字符串的副本。拷贝字符串用strncpy()更安全。第3个参数指明可拷贝的最大字符数

 //还是输入五个q开头的单词,但是对单词输入的长度有限制
#include <stdio.h>
#include <string.h>
#define SIZE 40
#define TARGSIZE 7
#define LIM 5 char * s_gets(char * st, int n); int main(void)
{
char qwords[LIM][TARGSIZE];
char temp[SIZE];
int i=; printf("Enter %d words beginning with q:\n",LIM);
while(i<LIM && s_gets(temp,SIZE))
{
if(temp[]!='q')
printf("%s doesn't begin with q!\n",temp);
else
{
strncpy(qwords[i],temp,TARGSIZE-);
qwords[i][TARGSIZE-] ='\0';
i++;
}
}
puts("Here are the words accepted:");
for (i=;i<LIM;i++)
{
puts(qwords[i]); //puts末尾自动加上换行符
} return ;
} char * s_gets(char * st, int n)
{
char * ret_val;
int i=; ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
if(ret_val)
{
while(st[i]!='\n' && st[i]!='\0')
i++;
if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
st[i]='\0';
else //其实是'\0'
while(getchar() != '\n') //会把缓冲区后续的字符都清空
continue;
}
return ret_val;
}

strncpy(target,source,n)把source中的n个字符或空字符之前的字符(先满足哪个条件就执行哪个)拷贝到target中。

如果source中的字符数小于n,则拷贝整个字符串,包括空字符。

但是有一种情况就是万一没有把末尾的空字符拷贝进去的话,就不是存的字符串了。所以一般要把n设置成比目标数组的大小少1,然后把数组最后一个元素设置为空字符。

代码如下:

 strncpy(qwords[i],temp,TARGSIZE-);
qwords[i][TARGSIZE-] ='\0';

这样做确保是一个字符串。

sprintf()函数

函数原型:int sprintf( char *buffer, const char *format [, argument] … );

注意:它函数声明在stdio.h中,而不是在string.h中;该函数和printf()有点像。但是它是把数据写入字符串中,而不是打印在显示器上。

第一个参数是目标字符串的地址。其余参数和printf()相同,即格式字符串和待写入项的列表

sprintf 是个变参函数,使用sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。

 //格式化字符串
#include <stdio.h>
#define MAX 20
char * s_gets(char * st, int n); int main(void)
{
char first[MAX];
char last[MAX];
char formal[*MAX+];
double prize; puts("Enter your first name:");
s_gets(first,MAX);
puts("Enter your last name:");
s_gets(last,MAX);
puts("Enter your prize money:");
scanf("%lf",&prize);
sprintf(formal,"%s, %-19s: $%6.2f\n",last,first,prize);
puts(formal); return ;
} char * s_gets(char * st, int n)
{
char * ret_val;
int i=; ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
if(ret_val)
{
while(st[i]!='\n' && st[i]!='\0')
i++;
if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
st[i]='\0';
else //其实是'\0'
while(getchar() != '\n') //会把缓冲区后续的字符都清空
continue;
}
return ret_val;
}

strchr函数:

函数原型:char *strchr(const char *s, int c)

如果s字符串中包含c字符,该函数返回指向s字符串首位置(指向字符)的指针;如果在字符串中未找到c字符,该函数则返回空指针;

strrchr函数:

函数原型:char *strrchr(const char * s,int c)

该函数返回s字符串中c字符的最后一次出现的位置(末尾的空字符也是字符串的一部分,所以在查找范围内)。如果未找到c字符,则返回空指针;

strstr函数:

函数原型:char *strstr(const char * s1, const char * s2);

返回值是指向s1字符串中s2字符串出现的首位置。如果在s1中没有找到s2,则返回空指针。

strpbrk函数:

函数原型:char *strpbrk(const char * s1, const char * s2);

如果s1字符中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针;如果在s1字符串中未找到任何s2字符串中的字符,则返回空指针。

size_t strlen(const char * s)

该函数返回s字符串中的字符数,不包括末尾的空字符

size_t类型是sizeof运算符返回的类型。

C规定sizeof运算符返回一个整数类型,但是并未指定是哪种整数类型

所以size_t在一个系统中可以是unsigned int,而在另一个系统中可以是unsigned long。

string.h头文件针对特定系统定义了size_t。这样就可以跨平台了,屏蔽平台之间的差异性。

//fgets()读入一行输入时,在目标字符串的末尾添加换行符

//处理末尾换行符的方法之一是循环检测换行符,然后替换成\0

 char * s_gets(char * st, int n)
{
char * ret_val;
int i=; ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
if(ret_val)
{
while(st[i]!='\n' && st[i]!='\0')
i++;
if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
st[i]='\0';
else //其实是'\0'
while(getchar() != '\n') //会把缓冲区后续的字符都清空
continue;
}
return ret_val;
}

有其他办法,使用strchr()代替s_gets():

 #include <stdio.h>

 char line[];
char * find; fgets(line, , stdin);
find = strchr(line, '\n');
if(find)
* find ='\0';

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

注意点:

 while(* string)

2 while(*string != '\0')

许多程序员会在while循环条件中使用第一种的测试条件;string指向空字符时,*string的值是0,即测试条件为假,while循环结束。作为C语言程序员应该熟悉方法,第二种的测试条件没有第一种简洁。

const char * string和const char string[]的区别:

从技术方面讲,两者等效且都有效;

使用方括号是为了提醒用户,实际处理的参数是数组;

如果要处理字符串,使用指针形式的话,实际参数可以是数组名,双引号括起来的字符串或声明为char *类型的变量。这种写法是为了提醒用户,实际参数不一定是数组;

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

演示1:嵌套函数的调用

 #include <stdio.h>

 void put1(const char *);
int put2(const char *); int main(void)
{
put1("If I'd as much money");
put1(" as I could spend,\n");
printf("I count %d characters.\n",
put2("I never would cry old chairs to mend.")); return ;
} void put1(const char * string)
{
while(*string)
putchar(* string++); } int put2(const char * string)
{
int count = ;
while(*string)
{
putchar(*string++);
count++;
}
putchar('\n'); return(count);
}

分析:使用printf()打印put2的值,但是为了获得put2的返回值,计算机必须先执行put2(),因此执行put2()的过程中,打印了put2中的字符串。

C语言常用字符串函数总结的更多相关文章

  1. C语言常用字符串函数

    string.h头文件中常用的函数 C 库函数 - strcat() char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所 ...

  2. php常用字符串函数小结

    php内置了98个字符串函数(除了基于正则表达式的函数,正则表达式在此不在讨论范围),能够处理字符串中能遇到的每一个方面内容,本文对常用字符串函数进行简单的小结,主要包含以下8部分:1.确定字符串长度 ...

  3. [转]MySQL常用Json函数和MySQL常用字符串函数

    MySQL常用Json函数:https://www.cnblogs.com/waterystone/p/5626098.html MySQL常用字符串函数:https://www.cnblogs.co ...

  4. js进阶js中支持正则的四个常用字符串函数(search march replace split)

    js进阶js中支持正则的四个常用字符串函数(search march replace split) 一.总结 代码中详细四个函数的用法 search march replace split 二.js进 ...

  5. Delphi常用字符串函数

    Delphi常用字符串函数   一.字符转换函数1.ord(input[i])返回字符表达式 input 左端起第 I 字符的ASCII 码值.2.CHAR()将ASCII 码转换为字符.如果没有输入 ...

  6. C语言入门(6)——C语言常用数学函数

    在编码过程中会经遇到数学运算,幸运的是C语言提供了非常丰富的数学函数库. 在数学中使用函数有时候书写可以省略括号,而C语言要求一定要加上括号,例如sin(pi/2)这种形式.在C语言的术语中,pi/2 ...

  7. MySQL最常用字符串函数

    字符串函数 是最常用的的一种函数,在一个具体应用中通常会综合几个甚至几类函数来实现相应的应用: 1.LOWER(column|str):将字符串参数值转换为全小写字母后返回 mysql> sel ...

  8. MySQL常用字符串函数

    字符串函数 是最常用的的一种函数,在一个具体应用中通常会综合几个甚至几类函数来实现相应的应用: 1.LOWER(column|str):将字符串参数值转换为全小写字母后返回 mysql> sel ...

  9. PHP 常用字符串函数整理

    PHP语言中的字符串函数也是一个比较易懂的知识.今天我们就为大家总结了将近12种PHP字符串函数,希望对又需要的朋友有所帮助,增加读者朋友的PHP知识库. 1.查找字符位置函数 strpos($str ...

随机推荐

  1. Android Studio 搭配 Tortoise SVN 安装问题汇总

    (1)Android studio 中想要使用SVN,但是在安装 1.9版本的SVN,会报SVN is too old(实际是太新了)的错误.所以只能下载1.8以下版本 (2)安装svn时,需要手动选 ...

  2. adb device offline 解决办法

    当电脑中的豌豆荚之类的应用打开的状态下 adb devices 显示连接状态 关闭手机助手之后,adb devices总显示 device offline 后来发现sdk  platform-tool ...

  3. JAVA基础知识总结7(抽象类 | 接口)

    抽象类: abstract 1.抽象:不具体,看不明白.抽象类表象体现. 2.在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abs ...

  4. sqlplus--sqlldr基础运用

    a.ctl load data                                         infile *                                     ...

  5. JQuery利用css()修改样式后 hover失效的解决办法

    执行完代码后发现写在样式表中的hover效果失效,改了好几遍差点重新写函数,后来发现很简单,是优先级的问题,css()中的内容覆盖了之前的样式 只需要在样式后写!important即可解决! .fil ...

  6. ubuntu 12.04 (64位)下安装oracle 11g过程及问题总结

    最近公司用到oracle,在ubuntu64位安装了一下,碰到了一些问题,在网上搜索到了一些答案,在此作为笔记记录下来. 1.首先下载oracle并解压不再赘述. 2.安装依赖包 sudo apt-g ...

  7. break跳出多重循环

    大家都知道break只能跳出当前的一个循环语句,如果碰到要跳出多个循环体,那么我们就该在循环体开头设置一个标志位,然后使用带此标志位的break语句跳出多重循环 jump: ;i<;i++){ ...

  8. python调用Java代码

    #coding:utf-8 #!/usr/bin/python from jpype import * import os.path,json from ethereum.utils import e ...

  9. 点石成金:访客至上的网页设计秘笈(原书第2版) 中文PDF版

    可用性设计是Web设计中最重要也是难度最大的一项任务.本书作者根据多年从业的经验,剖析用户的心理,在用户使用的模式.为扫描进行设计.导航设计.主页布局.可用性测试等方面提出了许多独特的观点,并给出了大 ...

  10. 关于C#中的算术运算

    使用中间变量交换两个int型变量的值: ; ; a = a+b; b = a-b; a = a-b; 相信大家很容易写出来,但考虑到边界值情况时会有一些有趣的事情. 我们知道有一个int.MaxVal ...