1.字符串的读取
字符的读取要注意以下几点:
- 以什么作为结束标志,如空格、回车、EOF
- 是否对溢出做检查
- 是否包含结尾的空格或回车
(1).scanf()
函数原型:int
scanf(
const
char
* restrict format,…),定义于<stdio.h>头文件
功能:从标准输入流stdin (标准输入设备,一般指向键盘)中读内容的通用子程序,可以读入多个字符
格式说明符:%c 读取一个字符 %s读取一个字符串,以空格作为结束标志
返回值:scanf函数返回成功读入的数据项数,读入数据时遇到了“文件结束”则返回EOF
注意:该函数读取到第一个空格之后就会结束读取,也就是用空格作为结束的标志。
#include <stdio.h>
int main()
{
char name[40];
printf("What's your name?\r\n");
scanf("%s",name);
printf("Hello,%s", name);
return 0;
}
输入:Angela Plains
输出:Hello,Angela
(2).getc()
函数原型:int getc( FILE *stream ),定义于<stdio.h>头文件
功能:从给定的输入流读取下一个字符
参数:stream — 读取字符的来源
返回值:成功时为获得的字符,失败时为 EOF
注意:该函数一次只能读取一个字符,但是可以结合while循环多次读取
示例:
int main()
{
char c;
c= getc(stdin); //从键盘读取
printf("读取的字符为:%c", c);
return 0;
}
(3).gets()
函数原型:char * gets ( char * str ),定义于<stdio.h>头文件
功能:从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在str指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为‘\0’空字符,并由此来结束字符串。
参数: str — 指向存储字符串的数组指针
返回值:读入成功,返回与参数buffer相同的指针;读入过程中遇到EOF(End-of-File)或发生错误,返回NULL指针。所以在遇到返回值为 NULL的情况,要用ferror或feof函数检查是发生错误还是遇到EOF。
注意:可以读取空格,并且以换行符或EOF作为结束标志,读取内容中不包含换行符,特别要注意的是这个函数不做溢出检查。
示例:
int main()
{
char name[20];
printf("What's your name?\r\n");
gets(name);
printf("Hello,%s", name);
return 0;
}
(4).fgetc()
函数原型:int fgetc(FILE *stream),定义于,stdio.h>
功能:从文件指针stream指向的文件中读取一个字符,读取一个字节后,光标位置后移一个字节
参数: stream — 读取字符的来源
返回值:成功时为获得的字符,失败时为 EOF。
示例:
int main()
{
char ch;
ch = fgetc(stdin);
printf("读取的字符为:%c", ch);
return 0;
}
(5).fgets()
函数原型:char *fgets( char *restrict str, int count, FILE *restrict stream ) (C99起),定义于<stdio.h>头文件
功能:从给定文件流读取最多 count - 1 个(最后要以’\0’结尾,所以是count-1)字符并将它们存储于 str
所指向的字符数组
参数:str — 指向char数组的指针
count — 写入的最大字符数,注意末尾的’\0’也要算入其中
stream — 读取数据来源的文件流
返回值:成功时为str
,失败时为空指针
注意:count包含末尾的’\0’,如果输入的字符长度超过count,则会被截断,前count-1个字符存储到指定位置中,最后以’\0’结束。可以输入空格,以换行符来结束读取,但读取的内容中会包含换行符!
示例:
//从键盘读取
int main()
{
char name[LENGTH];
printf("What's your name?\r\n");
fgets(name, LENGTH, stdin);
printf("Hello,%s", name);
return 0;
}
//从文件读入
#include <stdio.h>
int main(void)
{
FILE* fp;
char str[60];
/* 打开用于读取的文件 */
fp = fopen("D:/Desktop/text.txt", "r"); //打开指定路径的文件
if (fp == NULL) {
perror("打开文件时发生错误");
return(-1);
}
while(fgets(str, 60, fp) != NULL) {
/* 向标准输出 stdout 写入内容 */
printf("%s",str);
}
fclose(fp);
return(0);
}
(6).小结
(1)scanf()和gets()函数都不会检查数据是否溢出,而fgets()会进行检查,当溢出时丢弃超出的数据
(2)scanf()遇到空格会停止读取,读取的内容不会包含空格;gets()函数遇到回车会停止读取,读取的内容不包含回车;fgets()函数遇到回车停止读取,但是读取的内容会包含回车键
(3)总结起来,个人认为fgets()最好用,但要注意其中包含回车。除此之外,该函数还能从文件中读取内容。
2.字符串的长度
(1).strlen()函数
函数原型:size_t strlen(const char* str),定义于头文件<stdio.h>
功能:从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符’\0’为止,然后返回计数器值(长度不包含’\0’)
参数:str — 字符串起始地址
返回值:字符串的长度,不包含’\0’
示例:
int main()
{
char str[] = "Hello World!";
int len = strlen(str);
printf("%d\r\n",len);
return 0;
}
输出结果为:12
(2).sizeof()
该函数用于字符串时,计算的是字符串常量所占用的长度(包括字符串本身的长度和\0
),这也是和strlen的一个重要区别。
int main()
{
char str[] = "Hello World!";
int len = sizeof(str);
printf("%d\r\n",len);
return 0;
}
输出结果为:13
3.字符串复制
(1) strcpy()
函数原型:char *strcpy( char *restrict dest, const char *restrict src ),定义于<string.h>头文件
功能:复制 src
所指向的空终止字节字符串,包含空终止符,到首元素为 dest
所指的字符数组
参数:dest — 指向要写入的字符数组的指针 src — 指向要复制的空终止字节字符串的指针
返回值:返回 dest
的副本
注意:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串
示例:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch1[] = "Hello";
char ch2[10];
strcpy(ch2, ch1);
printf("ch2:%s\r\n",ch2);
return(0);
}
上面的代码执行之后,ch2[]中存放的内容是"Hello\0"。
(2).strncpy()
函数原型:char *strncpy( char *restrict dest, const char *restrict src, size_t count ),定义于<string.h>头文件
功能:复制 src
所指向的字符数组的至多 count
个字符(包含空终止字符,但不包含后随空字符的任何字符)到 dest
所指向的字符数组。
参数:dest — 指向要写入的字符数组的指针 src — 指向要复制的空终止字节字符串的指针 count — 要复制的最大字符数,包括’\0’
返回值:返回 dest
的副本
注意:如果不是将完整的 src 复制到dest 中,则需要在末尾添加终止符’\0’,否则字符串dest不完整。
示例:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch1[] = "Hello";
char ch2[10];
strncpy(ch2, ch1,2);
ch2[2] = '\0';
printf("%s\r\n", ch2);
return(0);
}
上面的程序运行之后,ch[0] = ‘H’,ch[1] = ‘e’。
需要注意的是,strncoy()不会在末尾加上’\0’,需要手动加上,而strcpy()会自动加上。
4.附加字符串
(1).strcat()
函数原型:char *strcat( char *restrict dest, const char *restrict src ),定义于<string.h>头文件
功能:把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)
参数:dest — 指向要后附到的空终止字节字符串的指针 src — 指向作为复制来源的空终止字节字符串的指针
返回值:返回 dest
的副本
注意:dest末尾的\0会被覆盖,src末尾的\0会一起被复制过去,最终的字符串只有一个\0。
示例:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch1[20] = "Hello";
char ch2[10] = " world!";
strcat(ch1, ch2);
printf("%s\r\n", ch1);
return(0);
}
输出:Hello World!
(2).strncat()
函数原型:char *strncat( char *restrict dest, const char *restrict src, size_t count ),定义于<string.h>头文件
功能:从字符串src的开头拷贝n个字符到dest字符串尾部,dest要有足够的空间来容纳要拷贝的字符串。如果n大于字符串src的长度,那么仅将src全部追加到dest的尾部。
参数:dest — 指向要后附到的空终止字节字符串的指针 src — 指向作为复制来源的空终止字节字符串的指针
count — 要复制的最大字符数
返回值:返回 dest
的副本
注意:dest要有足够的空间来容纳要拷贝的字符串。如果n大于字符串src的长度,那么仅将src全部追加到dest的尾部。
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch1[20] = "Hello";
char ch2[10] = " world!";
strncat(ch1, ch2,3);
printf("%s\r\n", ch1);
return(0);
}
输出:Hello wo(注意中间是有空格的)
5.字符串比较
(1).strcmp()
函数原型:int strcmp( const char *lhs, const char *rhs ),定义于<string.h>头文件
功能:以字典序比较二个空终止字节字符串
参数:lhs,rhs — 指向要比较的空终止字节字符串的指针
返回值:若字典序中 lhs
先出现于 rhs
则为负值;若 lhs
与 rhs
比较相等则为零;若字典序中 lhs
后出现于 rhs
则为正值
#include <stdio.h>
#include <string.h>
int main(void)
{
char *ch1 = "cb";
char *ch2 = "ab";
int res = strcmp(ch1, ch2);
printf("%d\r\n", res);
return(0);
}
(2) strncmp()
函数原型:int strncmp( const char *lhs, const char *rhs, size_t count ),定义于<string.h>头文件
功能:比较两个可能空终止的数组的至多 count
个字符。按字典序进行比较,不比较后随空字符的字
参数:lhs,rhs — 指向要比较的可能空终止的数组的指针 count — 要比较的最大字符数
返回值:若字典序中 lhs
先出现于 rhs
则为负值;若 lhs
与 rhs
比较相等,或若 count 为零,则为零;若字典序中 lhs
后出现于 rhs
则为正值。
示例:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *ch1 = "abcdE";
char *ch2 = "abcdF";
int res = strncmp(ch1, ch2,4);
printf("%d\r\n", res);
return(0);
}
由于只比较前4个字符,所以输出为0,即相等。
6.字符串查找
(1).strchr()
函数原型:char *strchr( const char *str, int ch ),定义于<string.h>头文件
功能:寻找 ch
(如同用 (char)ch 转换成 char 后)在 str
所指向的空终止字节字符串(转译每个字符为 unsigned char )中的首次出现位置。终止空字符被认为是字符串的一部分,并且能在寻找 ‘\0’ 时找到。
参数:str — 指向待分析的空终止字节字符串的指针 ch — 要搜索的字符
返回值:指向 str
找到的字符的指针,若未找到该字符则为空指针。
注意:虽然函数原型中 ch
是 int
类型的,但是在传参第时候还是要传入字符,传入后会被强制转换为其对应的编码值。还有返回的是地址,不是在字符串中的相对位置。
示例:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *str = "abcdefg";
char ch = 'd';
char* addr = strchr(str, ch);
printf("ch在str中的%d位置处(下标从0开始)!", (int)(addr - str));
return(0);
}
(2).strrchr()
函数原型:char *strrchr( const char *str, int ch ),定义在<string.h>头文件
功能:寻找 ch
(如同用 (char)ch 转换到 char 后)在 str
所指向的空终止字节串中(将每个字符转译成 unsigned char )的最后出现的位置。若搜索 ‘\0’ ,则认为终止空字符为字符串的一部分,而且能找到。
参数:str — 指向待分析的空终止字节字符串的指针 ch — 要搜索的字符
返回值:指向 str
中找到的字符的指针,或若找不到这种字符则为空指针。
注意:虽然函数原型中 ch
是 int
类型的,但是在传参第时候还是要传入字符,传入后会被强制转换为其对应的编码值。还有返回的是地址,不是在字符串中的相对位置。(同strchr()函数)
示例:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *str = "dbcdefg";
char ch = 'd';
char* addr = strrchr(str, ch);
printf("ch在str中的%d位置处(下标从0开始)!", (int)(addr - str));
return(0);
}
(3)strstr()
函数原型:char *strstr( const char* str, const char* substr ),定义于<string.h>头文件
功能:查找 substr
所指的空终止字节字符串在 str
所指的空终止字节字符串中的首次出现位置。不比较空终止字符
参数:str — 指向要检验的空终止字节字符串的指针 substr — 指向要查找的空终止字节字符串的指针
返回值:指向于 str
中找到的子串首字符的指针,或若找不到该子串则为 NULL 。若 substr
指向空字符串,则返回 str
。
#include <stdio.h>
#include <string.h>
int main(void)
{
char *str = "abcdefg";
char *substr = "cd";
char* addr = strstr(str, substr);
printf("substr在str中的%d位置处(下标从0开始)!", (int)(addr - str));
return(0);
}
7.字符串分割
strtok()
函数原型:char *strtok( char *restrict str, const char *restrict delim ),定义在<string.h>头文件
功能:分解字符串为一组字符串
参数:str — 指向待分割的字符串的指针 delim — 指向分隔符字符串或字符的指针
返回值:该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
实现原理:在 str
字符串中找到分隔符,然后将其替换为’\0’,然后就结束了。注意即使 str
中存在多个分割符,调用一次只要遇到一个分割符就会停止了,再进行一次调用就会替换第二个分割符,直到找不到分隔符则返回 NULL 。
注意:**strtok函数会破坏被分解字符串的完整,调用前和调用后的str
已经不一样了。**在首次调用时,str指向要分解的字符串,之后再次调用要把str设成NULL。
示例:
#include<string.h>
#include<stdio.h>
int main(void)
{
char str[] = "192.168.100.56";
char delim[] = "."; //以 '.'作为分隔符,注意要传入字符串而不是字符
char* p;
p = strtok(str, delim);
printf("%s\r\n", p);
while (p != NULL)
{
p = strtok(NULL, delim);
printf("%s\r\n", p);
}
return 0;
}
输出如下:
192 168 100 56 (null)
其中"(null)"是当 p = NULL时进行打印输出的。
上面的示例需要注意以下几点:
- 第6行的str要定义为字符串数组,如果定义定义为字符串指针会越界,原因未知
- 第7行的分隔符是".",即是一个字符串而不是单独的一个 ‘.’ 字符,需要特别注意
- 第9行第一次调用
strtok()
函数,str要指向被分割的字符串的地址 - 第13行开始的第2次及后面的调用,
strtok()
函数的第一个参数要传入NULL
8.字符串转数值
数值抓换的所有函数都定义在 <stdlib.h>头文件中。
1.转浮点数
(1)atof()
函数原型:double atof( const char* str )
参数: str 要转换的字符串,如"3.1415"
返回值:转换得到的duoble类型的浮点数
注意:如果输入字符串中存在非法字符,则从非法字符开始的后面部分都为0,如"3.14a15"会被转换为3 .14。
示例:
#include<stdlib.h>
#include<stdio.h>
int main(void)
{
char str[] = "3.1415926";
double f = atof(str);
printf("%.10f\n", f); //要用 .10f 来指定输出的小数位数,默认输出6为小数
return 0;
}
(2)strtof(), strtod(), strtold()
函数原型:float strtof( const char *restrict str, char **restrict str_end );
double strtod( const char *restrict str, char **restrict str_end );
long double strtold( const char *restrict str, char **restrict str_end );
参数: str — 指针待转换的字符串的指针 str_end — 指向指向字符指针的指针
返回值:转换结果
#include<stdlib.h>
#include<stdio.h>
int main(void)
{
char str[] = "3.1415926 This is a test!";
char* ptr;
double f= strtof(str,&ptr);
printf("数字部分为:%.10f\n", f);
printf("字符串部分为:%s",ptr);
return 0;
}
输出结果如下:
数字部分为:3.1415925026 字符串部分为: This is a test!
2.转整数
(1) atoi()、atil()、atoll()
函数原型:int atoi( const char *str ); long atol( const char *str ); long long atoll( const char *str );
参数:指向待转换的字符串的指针
返回值:分别为int型、long int型、long long int型
示例:
#include<stdlib.h>
#include<stdio.h>
int main(void)
{
char str[] = "1024";
int inter = atoi(str);
printf("%d\n", inter);
return 0;
}
(2) strtol()、strtoll()
函数原型:long strtol( const char *restrict str, char **restrict str_end, int base );
long long strtoll( const char *restrict str, char **restrict str_end, int base );
参数:str — 指向待转换的字符串的指针
str_end — 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符,为指针的指针
base — 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0,这个参数用于指定字符串中数字的进制
示例:
#include<stdlib.h>
#include<stdio.h>
int main(void)
{
char str[] = "1111 This is a test!";
char* ptr;
int inter = strtol(str,&ptr,2);
printf("数字部分为:%d\n", inter);
printf("字符串部分为:%s",ptr);
return 0;
}
输出如下:
数字部分为:15 字符串部分为: This is a test!
(3) strtoul(), strtoull()
功能:将字符串转换为无符号整数值
这两个函数的用法与上面两个一致,区别在于转换结果是有符号还是无符号。
9.大小写转换
(1) 转小写 tolower()
函数原型:int tolower( int ch ),定义于<ctype.h>头文件
功能:将字符转换为小写
参数:ch — 待转换的字符
返回值: ch 的小写
示例:
#include<stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char str[] = "Hello World!";
printf("转换前:%s\r\n", str);
for (int i = 0; i < strlen(str); i++)
str[i] = tolower(str[i]);
printf("转换后:%s\r\n", str);
return 0;
}
输出如下:
转换前:Hello World! 转换后:hello world!
(2)转大写 toupper()
函数原型:int toupper( int ch );
功能:将字符转换为大写
参数:ch — 待转换的字符
返回值: ch 的大写
示例:
#include<stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char str[] = "Hello World!";
printf("转换前:%s\r\n", str);
for (int i = 0; i < strlen(str); i++)
str[i] = toupper(str[i]);
printf("转换后:%s\r\n", str);
return 0;
}
输出如下:
转换前:Hello World! 转换后:HELLO WORLD!
10.字符分类
这些函数使用都比较简单,这里只给出函数名和功能。这些函数实现的功能很简单,也可以自己实现。
<ctype.h>
函数名 | 功能 |
---|---|
isalnum | 判断一个字符是否为字母或数字 |
isalpha | 判断一个字符是否为英文字母 |
islower | 判断一个字符是否为小写字母 |
isupper | 判断一个字符是否为大写字母 |
isdight | 判断一个字符是否为数字 |
isxdight | 判断一个字符是否为十六进制的字符 |
iscntrl | 判断一个字符是否为控制字符 |
isgraph | 判断一个字符是否为可显示的字符 |
isspace | 判断一个字符是否为空格 |
isblank (C99) | 判断一个字符是否为空格字符 |
isprint | 判断一个字符是否为可打印字符 |
ispunct | 判断一个字符是否为标点符号 |