第11章 字符串和字符串函数
11.1 表示字符串和字符串I/O
字符串是以空字符'\0'结尾的char类型数组
11.1.. 在程序中定义字符串
1.字符串字面量(字符串常量)
用双引号括起来的内容称为字符串字量,其中‘\0’也作为字符存储在字符串中。
从ANSIC开始,如果字符串字面量之间没有间隔,或者用空白字符分割,c将其视为串联起来的字符串。
字符串属于静态存储类别
2. 字符串数组和初始化
例:char n[] ;"hello"
3. 数组和指针
数组形式:在内存中开辟了一块空间,每个元素被初始化为字符串对应的字符。
即当程序开始运行时才会给该数组分配空间,此时,字符串有两个副本,一个静态内存中的字符串字面量,另一个是数组中的字符串。
指针形式:只需要为指针变量创建一个存储位置即可,同时,字符串仅有一个即静态内存中的字符串字面量,指针只存储字符串字面量的地址。
总之:初始化数组把静态存储区的字符串拷贝到数组,初始化指针只把字符串地址拷贝给指针。
4. 数组和指针的区别
如果不修改字符串则,尽量不使用指针指向字面量。
5. 字符串数组
const char *mytalents [n]={ "qwerty" "qwertydf" }; const char yourtalents [n][m]={ "qwerty" "qwertydf" };
可以把mytalens当做矩形二维数组,把yourtalens当做不规则的数组
要改变字符串或为字符串输入预留空间不要使用指向字符串字面量的指针。
11.1.2 指针和字符串
11.2 字符串输入
11.2.1 分配空间
要先分配空间
11.2.2 不幸的gets()函数
gets()只知道数组开始,并不知道数组中有多少元素,输入过长会导致缓冲区溢出。
puts()自动添加换行符。
11.2.3 gets()替代品
1.fgets()
第二个参数指明了读取字符的最大数量,如果该参数为n,n大于数组大小,将读取n-1字符,最后一位赋’\0’,n小于数组大小打印到第一个换行符为止。
如果n小于数组大小,fgets()读取到一个换行符,会把它存储在字符串中,gets()则会丢弃换行符。
fgets()第三个参数指明要读取的文件如果从键盘输入数据,则stdin(标准输入)
该函数返回指向char类型指针,如果成功,则和传入该函数第一个参数相同,如果读到文件结尾,将返回空指针。
fpus()第二个参数,指明要写入的文件,显示在计算机屏幕,是stdout。
2.gets_s函数
第一个参数:输入的数组名,第二个参数:字符数。
gets()读到换行符会丢弃它,
如果gets()读取到最大字符数都没有遇到换行符,会把目标数组中的首字符设置为空字符,读取并丢弃随后的输入,直到遇到换行符或文件结尾。
3. s_gets()函数
读取整行输入并用空字符代替换行符,或者读取一部分输入,并丢弃其余部分。
char *s_gets(char *st ,int n) { char *ret_val; int i=0; ret_val=fgets(st,n,stdin); if(ret_val)//表示fgets没有读到文件结尾,成功读取了
{
while(st[i]!='\o'&&st[i]!='\n')
i++;
if(st[i]=='\n')
st[i]='\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;
}
11.2.4 scanf()函数
以第一个非空白字符字符作为开始,以下一个空白字符(空格,空行,制表符,或换行符)作为字符串结束。
11.3 字符串输出
11.3.1 puts()函数
puts()在显示字符串时会自动在末尾添加一个换行符。
11.3.2 fputs()函数
fputs()第二个参数,指明要写入的文件,显示在计算机屏幕,是stdout。不会添加换行符。
11.3.3 printf()函数
11.4 自定义输入输出函数
11.5 字符串函数
11.5.1 strlen()函数
统计字符串长度
strlen()只有一个参数 遇到\0结束
11.5.2 strcat()函数
用于拼接字符串,接受两个字符串作为参数。把第二个字符串备份附加到第一字符串末尾,(把第一个字符串的\0替换调)第二个字符串不变。
该函数返回第一个参数。(即第一个字符串的指针)
11.5.3 strncat函数
第三个参数为指定添加的最大字符数
11.5.4 strcmp()函数
比较两个字符串,strcmp()会依次比较每个字符,直到发现第一对不同字符,(按照机器排序序列)返回两个数差值。
strncmp()第三个参数为指定比较的字符数。
11.5.5 strcpy()和strncpy()
拷贝字符串,把第二个参数赋值给第一个参数。
strcpy()返回类型是char*,该函数返回的是第一个参数的值。
strncpy()第三个参数为指定可拷贝的最大字符数。
11.5.6 sprintf()
sprintf()声明在stdio.h
该函数第一个参数为目标字符串地址,接下来和printf()使用方法一致。
11.5.7 其他字符串函数
char *strcpy (char*restrict s1, const char*restrict s2)
以上为把s2指向字符串(包括空字符)拷贝到s1指向位置,返回值为s1
char *strncpy (char*restrict s1, const char*restrict s2,size_t n)
以上为把s2指向字符串(包括空字符)拷贝到s1指向位置,拷贝的字符数不超过n,返回值为s1。
如果源字符串少于n,目标字符串就以拷贝的空字符串结尾。
如果超过n,就不拷贝空字符。
char *strcat (char*restrict s1, const char*restrict s2)
以上为把s2指向字符串拷贝到s1指向字符串末尾,s2字符串第一个字符,将覆盖s1字符串末尾的空字符。
char *strncat (char*restrict s1, const char*restrict s2 , size_t n)
以上为把s2指向字符串中n个字符拷贝到s1指向字符串末尾,s2字符串第一个字符,将覆盖s1字符串末尾的空字符。
char *strcmp (const char* s1, const char* s2)
如果s1字符串在机器排序序列中位于s2字符串末尾,该函数返回一个正数,相等返回零,反之为负数。
char *strcmp (const char* s1, const char* s2, size_t n)
只比较前n个字符,如果s1字符串在机器排序序列中位于s2字符串末尾,该函数返回一个正数,相等返回零,反之为负数。
char *strchr (const char* s, int c)
如果s字符串中包括字符c,该函数返回s字符串中首次出现c字符的位置,未找到则返回空指针。
char *strpbrk (const char* s1, const char* s2)
如果s1中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针,未找到则返回空指针。
char *strchr (const char* s, int c)
返回s1字符串中最后一次出现c字符的位置,未找到返回空指针。
char *strstr (const char* s1, const char* s2)
返回s1中首次出现s2字符串的位置,未找到则返回空指针。
size_t strlen(const char *s)
返回s字符串中的字符数,不包括空字符。
11.6 字符串示例
11.6.2 选择排序法
利用for循环把每个元素与首元素比较,如果待比较元素在当前首元素前面,则交换两者,循环结束后首元素包含指针指向机器排序序列最考前的字符。然后外层for循环重复这一动作。
11.7 ctype.h字符串函数和字符串
11.8 命令行参数
int main (int argc , char *argv[])
第一个argc为命令行中字符串数量,argv为参数值
例:hello resistance is futile
则,argc为4 argv[]依次存储,hello resistance is futile
11.9 把字符串转化为数字
包含在stdlib中
atoi()字母数字转化为整数,
atof()字符串转化为double
atol()字符串转化为long类型
strtol()转化为long类型
strtoul()转化为unsigned long 类型
strtod()转化为double类型。
strol()和stroul()可以指定进制转化。
long strtol(const char *restrict nptr char **restrict endptr,int base)
nptr为待转化字符串的指针,endptr是指针的地址,该指针被设置为标识输入数字结束字符的地址。
即当nptr为输入为10时,endptr指向‘\0’
nptr输入为10at时,endptr指向‘a’
11.13 编程练习
1、设计并测试一个函数,可以从输入读取n个字符(包括空格、制表符和换行符),把结果存储在一个数组中,这个数组的地址通过参数来传递
#include<stdio.h> #include<stdlib.h> char *s_gets(char *st,int n); int main(void) { int n=0; puts("请输入字符数组大小"); scanf("%d",&n); while (getchar()!='\n') continue; char st[n]; s_gets(st,n); system("pause"); return 0; } char *s_gets(char *st,int n) { int i=0; puts("请输入字符"); while (i<n) { *(st+i)=getchar(); i++; } i=0; while (i<n) { printf("%c",*(st+i)); i++; } puts(""); return st; }
2、修改并测试练习1中的函数,使得可以在n个字符后,或第一个空格、制表符、换行符后停止读取输入,由上述情况中最先被满足的那个终止读取(不能使用scanf()函数)
#include<stdio.h> #include<stdlib.h> #include<ctype.h> char *s_gets(char *st,int n); int main(void) { int n=0; puts("请输入字符数组大小"); scanf("%d",&n); while (getchar()!='\n') continue; char st[n]; s_gets(st,n); system("pause"); return 0; } char *s_gets(char *st,int n) { int i=0; puts("请输入字符"); while (i<n) { *(st+i)=getchar(); if(isspace(*(st+i))) /*利用isspace()判断输入是否是空格、制表符或者换行符*/ break; i++; } i=0; while (i<n) { printf("%c",*(st+i)); i++; } puts(""); return st; }
3、设计并测试一个函数,其功能是读取输入行里的第一个单词到数组,并丢掉该 行中的其他字符。一个单词的定义是一串字符其中不含空格、制表符或换行符
#include<stdio.h> #include<stdlib.h> #include<ctype.h> void word(char *p); int main(void) { char a[81]; puts("Input the string."); gets(a); word(a); puts(a); system("pause"); return 0; } void word(char *p) { int begin,end; for(begin=0;isspace(*(p+begin));begin++) continue;//为了找到单词开头 for(end=begin;!isspace(*(p+end));end++) continue;//找到单词结尾 *(p+end)='\0'; for(;*(p+begin)!='\0';p++)//修改排序 *p=*(p+begin); *p='\0'; }
5、设计并测试一个函数,其功能 是搜索由函数的第一个参数指定的字符串,在其中查找由函数的第二个参数指定的字符的第一次出现的位置。如果找到,返回指向这个字符 的指针:如果没找到,返回空字符(这种方式和strchr()函数的功能一样)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include<stdio.h> #include<stdlib.h> char *mystrchr(char *p,char ch); int main(void) { char a[81]; char b; char *p; do{ puts("Input a string:"); gets(a); puts("Input the char you want to find in the string:"); b=getchar(); getchar(); p=mystrchr(a,b); if(p) { puts("Find!"); puts(p); } else puts("Can't find!"); puts("Input any char except q to quit."); gets(a); } while(*a!='q'); puts("Quit."); system("pause"); return 0; } char *mystrchr(char *p,char ch) { char *p_save=p; if(*p=='\0') return NULL; while(1) { if(*p==ch) { return p_save; } else { if(*++p=='\0') return NULL; p_save=p; } } }
6、编写一个函数is_within()。它接受两个参数,一个是字符,另一个是字符串指针。其功能 是如果字符 在字符串中,就返回一个非0值(真);如果字符不在字符串中,就返回0值(假)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include<stdio.h> #include<stdlib.h> int is_within(char *p,char ch); int main(void) { char ch; char p[88]; int b; do { puts("请输入字符串"); gets(p); puts("请输入查找的字符"); ch=getchar(); while (getchar()!='\n') continue; b=is_within(p,ch); if (b) puts("查询到值"); else puts("未查询到值"); puts("如果结束,请输入q,不结束请输入其他任意值"); ch=getchar(); while (getchar()!='\n') continue; } while (ch!='q'); } int is_within(char *p,char ch) { while(*p!='\0') { if (*p==ch) return 1; p++; } return 0; }
16、编写一个程序,其功能是读取输入,直到遇到文件结尾,并把文件显示出来。要求程序可以识别并执行下面的命令行参数:
-p 按照原样显示输出
-u 把输入全部转换为大写
-l 把输入全部转换成小写