写在前面:本文基于上课所用PPT及《C Primer Plus》第6版,代码也是多源于此。字符串函数一直是本人弱项,终于熬过了考试周,来总结一下为C语言的期末机试做准备。
字符串:以==空字符(\0)==结尾的char类型数组。
put()函数只显示字符串,自动在显示的字符串末尾加上换行符。
#include
#define MSG "I am a symbolic string constant."
#define MAXLENGTH 81
int main (void) {
char words[MAXLENGTH] = "I am a string in an array.";
const char *pt1 = "Something is pointing at me.";
puts ("Here are some strings:");
puts ("using puts:");
puts (MSG);
puts ("using printf:");
printf ("%s", MSG);
puts (pt1);
return 0;
}
字符串常量属于静态存储类别(static storage class),如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命期内存在,即使函数被调用多次。双引号括起来的内容被视为指向该字符串储存位置的指针。这类似于把数组名作为指向该数组位置的指针。
定义字符串数组时,必须让编译器知道需要多少空间。一种方法是用足够空间的数组储存字符串。
const char m1[40] = " Limit yourself.";
const char m2[40] = " 'L', 'i', 'm', 'i', 't', ' ', 'y', 'o', 'u', 'r', 's', 'e', 'l', 'f', '.', '\0'};
const char m3[40] = " 'L', 'i', 'm', 'i', 't', ' ', 'y', 'o', 'u', 'r', 's', 'e', 'l', 'f', '.'};
m1,m2是字符串,m3是字符数组,因为末尾无’\0’。
制定数组大小时,要确保数组的元素个数至少比字符串长度多1。所有未被使用的元素都被自动初始化为0(char形式的空字符)。
省略数组初始化声明中的大小,编译器会自动计算数组的大小。
const char m1[] = " Limit yourself.";
通常,字符串都作为可执行文件的一部分储存在数据段中。当把程序载入内存时,也载入了程序中的字符串。字符串储存在静态存储区(static memory)中。但是,程序在开始运行时才会为该数组分配内存。此时,才将字符串拷贝到数组中。此时字符串有两个副本,一个是在静态内存中的字符串字面量,另一个是储存在ar1数组中的字符串。
在数组形式中,ar1是地址常量,…
char *name;
scanf ("%s", name);
可能会通过编译(可能给出警告),读入name时可能会擦写掉程序中的数据或代码,从而导致程序异常终止。因为scanf()要把信息拷贝至参数指定的地址上,而此时该参数是个未初始化的指针,name可能指向任何地方。
最简单的方法是,在声明时显式指明数组的大小;
scanf()函数和%s转换说明只能读取一个单词,遇空格停止。
gets()读取整行输入,直至遇到换行符,然后丢弃换行符,储存其余字符,并在这些字符的末尾添加一个空字符使其成为一个C字符串。经常和puts()配对使用。
**gets()无法检查数组是否装得下行。**如果输入的字符串过长,会导致缓冲区溢出(buffer overflow),即多余的字符超出了指定的目标空间。如果这些多余的字符只是占用了尚未使用的内存,就不会立即出现问题;如果它们擦写掉程序中的其他数据,会导致程序异常中止;或者还有其他情况。
空字符vs空指针
scanf()从第一个非空白字符作为字符串的开始。如果使用%s说明,以下一个空白字符(空格、空行、制表符或换行符)作为字符串的结束(字符串不包括空白字符)。如果制定了字段宽度,如%10s,那么scanf()将读取第10个字符或读到第1个空白字符停止(先满足的条件即是结束输入的条件)。
函数在遇到空字符时停止输出,所以必须确保有空字符
用于统计字符串的长度。需要#include
strcat()函数用于拼接字符串,接受两个字符串作为参数。该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后形成的新字符串作为第1个字符串,第2个字符串不变。strcat()函数的类型是char*,返回第1个参数,即拼接第2个字符串后的第1个字符串的地址。
#include
#include
#define SIZE 80
char * s_gets (char * st, int n);
int main (void) {
char flower[SIZE];
char addon [] = "s smell like old shoes.";
puts ("What is your favorite flower?");
if (s_gets (flower, SIZE)) {
strcat (flower, addon);
puts (flower);
puts (addon);
}
else {
puts ("End of file encountered!");
}
puts ("bye");
return 0;
}
char * s_gets (char * st, int n) {
char * ret_val;
int i = 0;
ret_val = fgets (st, n, stdin);
if (ret_val) {
while (st[i] != '\n' && st[i] != '\0') {
i++;
}
if (st[i] == '\n') {
st[i] = '\0';
}
else {
while (getchar() != '\n') {
continue;
}
}
}
return ret_val;
}
strcat()函数无法检查第1个数组是否能够容纳第2个字符串。如果分配给第1个数组的空间不够大,多出来的字符串溢出到相邻存储单元是就会出现问题。
int strcmp (const char *str1, const char *str2);
返回值:负整数/0/正整数
#include
#include
int main (void) {
char name1[50], name2[50];
int diff;
printf ("Name of Country 1:");
gets (name1);
printf ("Name of Country 2:");
gets (name2);
diff = strcmp (name1, name2);
if (diff > 0) {
printf ("%s > %s\n", name1, name2);
}
else {
printf ("%s <= %s\n", name1, name2);
}
return 0;
}
strcmp函数比较的是字符串,不是整个数组。可以用来比较储存在不同大小数组中的字符串。字符串1>2,返回负数。
在某些情况下,可用strcmp()函数来处理结束输入的情况,如strcmp(str,"***end***")==0
可以比较到字符不同的地方,也可以只比较第3个参数指定的字符数。例如,查找以"astro"开头的字符串,可以限定函数只查找这5个字符。strncmp(list[i],"astro",5)
#include
#include
int main (void) {
char name[50], bakName[50];
puts ("input a name:");
gets (name);
strcpy (bakName, name);
printf ("You input is %s\n",bakName);
return 0;
}
把第2个字符串拷贝给第1个字符串。储存第1个字符串的数组需要有足够的空间。
1.strcpy的返回值是第1个参数的值
2.第1个参数不必指向数组的开始,可以用于拷贝数组的一部分。
int isalnum(int c):判断是否有数字及字母
int isalpha(int c):判断是否有字母
int isdigit(int c):判断是否是十进制数字
int islower(int c):判断是否是小写字母
int isupper(int c):判断是否是大写字母
int tolower(int c):转化成小写字母
int toupper(int c):转换成大写字母