C语言知识-零零散散(二)
字符串处理函数
gets和puts函数
/*
功能:从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间。
参数:char *str,str是一个指针变量名,也可以一个字符数组名。
返回值:读入成功,返回和参数str相同的指针;失败,返回NULL指针。
*/
char *gets(char *str);
/*
功能:输出字符串。
参数:s是要输出的字符串,可以字符指针变量名、字符数组名、或者是字符常量。
返回值:成功,该函数返回一个非负值,如果发生错误则返回-1。
*/
int puts(const char *s);
gets函数,从标准设备上获取一个字符串,字符串可以包括空格,直到接收到换行字符或者字符串结束标志才停止。此函数有一个比较严重的缺陷,不能检查数组是否能装下输入行。例如,定义一个字符数组 char str[10];
,如果使用gets输入的字符串为“hello”,可以正常的获取,但是,如果输入的是"hello world!",此时gets函数就会访问未分配的内存空间,那么就会引起程序的错误。
puts函数,从标准设备上输出一个字符串,输出结果时自带\n
换行符。
fgets和fputs函数
/*
功能:从 stream 流中读取 size 个字符存储到字符指针变量 s 所指向的内存空间。
参数:s表示一个字符串的首地址,size表示需要读取的字符串的长度,stream 表示从何种流中读取,可以是标准输入流 stdin(读取键盘输入的字符串),也可以是文件流。
返回值:返回一个指向字符串中第一个字符的地址的指针。
*/
char *fgets(char *s, int size, FILE *stream);
/*
功能:将str所指定的字符串写入到stream指定的文件中。
参数:s代表要输出的字符串的首地址,可以是字符数组名、字符指针变量名;stream 表示向何种流中输出,可以是标准输出流 stdout(即屏幕输出),也可以是文件流。
返回值:成功返回0,失败返回-1。
*/
int fputs(const char * str, FILE * stream);
fgets函数,如果输入字符串长度的大小小于原始指针对应区域的大小,会在字符串输入完成时自动加入"\n\0"
;如果输入字符串长度的大小大于等于原始指针对应区域的大小,等待字符串结束标志后,把数组的最后一个元素替换为'\0'
。
fputs函数,显示字符串,和puts函数相比,fgets可以向任何流输出,但是fputs函数输出时,系统不会自动添加换行符。
scanf和printf函数
/*
功能:从标准输入 stdin 读取格式化输入
参数:格式控制字符串,变量地址列表
返回值:返回正确格式输入变量的个数;遇到错误或者EOF时,返回-1。
*/
int scanf( const char *format [,argument]... );
/*
功能:发送格式化输出到标准输出 stdout
参数:格式控制字符串,变量列表
返回值:如果成功,则返回写入的字符总数,否则返回一个负数。
*/
int printf(const char *format, ...)
scanf函数,当输入一个字符串时,该函数不接收空格字符,遇到空格认为是字符串的结束。函数的返回值,当按照格式输入时,返回正确输入的个数,当遇到第一个输入未成功读取时,后面的都不再接收,如果在接收n个数据时未成功读取,返回值为n-1;当遇到错误或者EOF(ctrl+z)时,返回-1。
scanf函数的其他用法(与正则表达式结合):
1.可以接收空格,遇到换行结束
char* arr[100];
scanf("%[^\n]", arr);
2.限定接收数据的宽度
char* arr1[100];
char* arr2[100];
scanf("%3s%4s", arr1, arr2); //当输入一串字符时,arr1接收前三个,紧接着arr2接收四个,其余的舍弃
int a, b;
scanf("%3d%4d", &a, &b); // 从键盘输入一串数组,a取三位,b取四位。
3.屏蔽数据类型,%* d表示屏蔽数字,%*c表示屏蔽字符
char* arr[100];
scanf("%*d%s", arr); // 屏蔽前面输入的数字
sacnf("%*c%s", arr); // 屏蔽第一个输入的字符
4.屏蔽一个区间内定义的数据
char c;
scanf("%*[0-9]%c", &c); // 屏蔽0-9数字
scanf("%*[a-z]%c", &c); // 屏蔽a-z字母
printf函数的各种打印形式,如下面的例子:
printf("%10.3lf\n", 12.3456); //当输出是数字时,m.n,小数点后表示精度,小数点前表示保留的总位数,如果m>n,输出的数字位数小于m时,不足的在左边补空格:当m<n时,整数部分正常输出,小数部分保留n位有效数字
printf("%06d\n", 66); // 不足6位,在前面补0
printf("%6d\n", 66); // 不足6位,在前面补空格,默认时右对齐
printf("%-6d\n", 66); // 加上'-',输出方式为左对齐,不足6位,数字后面补空格
printf("%6s\n", "abc"); // 和数字的输出一样,不足6个字符,在字符串前面补空格
printf("%6.4s\n", "abcde"); // 对于输出字符串,m.n, m表示要输出的总长度,n表示保留几个字符
strlen函数
/*
功能:计算目标字符串长度,不包含字符串结束符‘\0’
参数:字符串首地址,可以时字符数组名,字符串指针变量,或者字符串常量
返回值:字符串s的长度,size_t为unsigned int类型
*/
size_t strlen(const char *s);
strlen函数所求的是字符串的实际长度,即不包含’\0‘,需要注意的是,strlen并不能求出字符数组的长度。可以看下面例子:
int a = strlen("hello");
char* s1 = "hello";
int b = strlen(s1);
char s2[] = "hello";
int c = strlen(s2);
char s3[10] = {'h','e','l','l','o','\0'};
int d = strlen(s3);
printf("%d, %d, %d, %d\n",a,b,c,d);
strcpy和strncpy函数
/*
功能:把src所指向的字符串复制到dest所指向的空间中,'\0'也会拷贝过去
参数:
dest:目的字符串首地址
src:源字符首地址
返回值:
成功:返回dest字符串的首地址
失败:NULL
*/
char *strcpy(char *dest, const char *src);
/*
功能:把src指向字符串的前n个字符复制到dest所指向的空间中,是否拷贝结束符看指定的长度是否包含'\0'。
参数:
dest:目的字符串首地址
src:源字符首地址
n:指定需要拷贝字符串个数
返回值:
成功:返回dest字符串的首地址
失败:NULL
*/
char *strncpy(char *dest, const char *src, size_t n);
strcpy函数,把源字符串src拷贝到目的字符串dest中,拷贝的时候会把 '\0’也一起拷贝过去。这里需要注意的是,当目标字符串的长度比源字符串短时,会造成缓冲溢出的错误。所以使得strcpy进行字符串拷贝时,具有安全隐患。当调用strcpy时,可以判断函数的返回值是否为NULL,来确定调用是否成功。
char s1[] = "hello";
char s2[10];
if(strcpy(s2, s1) != NULL){
printf("OK\n");
}
strcpy函数,会拷贝源字符串中的’\0’,如果目的字符串已经初始化了,并且比源字符串长,那么只会覆盖源字符串的长度,如下面的例子,输出的结果为输出字符串为 “hello”,但是s2中的内容并没有被覆盖掉,s2={’h‘,‘e’,‘l’’,‘l’,‘o’,’\0’,‘o’,r’’,‘l’,‘d’,’\0’}
char s1[] = "hello";
char s2[] = "helloworld";
int i=0;
strcpy(s2, s1);
printf("%s\n", s2);
for(i=0; i<sizeof(s2); i++){
printf("%c", s2[i]);
}
printf("\n");
strncpy函数,从源字符串中拷贝指定长度的字符到目的字符中,所以拷贝过程中,并不保证目的字符串以’\0’为结尾。所以我们在拷贝完成以后,需要手动的添加’\0’标志。
char s1[] = "hello world";
char s2[20];
strncpy(s2, s1, 11);
//s2[11] = 0;
s2[11] = '\0';
printf("%s\n",s2);
这里需要注意的是,如果源字符串的长度小于拷贝的长度n,那么会把目的字符串剩下的部分全部置为 0。如下面代码,s2的初始值是"sssssssssssssssssss",当把s1拷贝给s2时,由于s1的长度小于s2,所以s2接收到"hello world\0"后,把剩余的部分全部置为’\0‘。
char s1[] = "hello world";
char s2[20] = "sssssssssssssssssss";
int i=0;
strncpy(s2, s1, 20);
printf("%s\n",s2);
for(i=0; i<20; i++){
printf("%c", s2[i]);
}c
printf("\n");
strcat和strncat函数
/*
功能:将src字符串连接到dest的尾部,‘\0’也会追加过去
参数:
dest:目的字符串首地址
src:源字符首地址
返回值:
成功:返回dest字符串的首地址
失败:NULL
*/
char *strcat(char *dest, const char *src);
/*
功能:将src字符串前n个字符连接到dest的尾部,‘\0’也会追加过去
参数:
dest:目的字符串首地址
src:源字符首地址
n:指定需要追加字符串个数
返回值:
成功:返回dest字符串的首地址
失败:NULL
*/
char *strncat(char *dest, const char *src, size_t n);
strcat函数,把源字符串追加到目的字符串后,目的字符串的长度一定要大于等于两个字符串的长度和,否则会发生访问越界的错误。在追加的时候,目的字符串的’\0’会被覆盖掉,追加完成以后,然后再在结尾加入’’\0’。
char arr1[20] = "hello";
char arr2[] = "world";
char* arr = strcat(arr1, arr2);
printf("%s\n", arr1);
printf("%s\n", arr);
strncat函数,用于将n个字符追加到字符串的结尾,同样的目的字符要足够长,追加过程中,会把目的字符串最后的’\0’覆盖掉,字符追加完成后,再追加’\0’。
char arr1[10] = "hello";
char arr2[] = "world";
char* arr = strncat(arr1, arr2, 3);
printf("%s\n", arr1);
printf("%s\n", arr);
再使用strncat函数时,如果n大于源字符串的长度,那么只取’\0’结束符前的字符,示例如下:
char arr1[10] = "hello";
char arr2[] = "wo\0rld";
char* arr = strncat(arr1, arr2, 5);
printf("%s\n", arr1);
printf("%s\n", arr);
strcmp和strncmp函数
/*
功能:比较 s1 和 s2 的大小,比较的是字符ASCII码大小。
参数:
s1:字符串1首地址
s2:字符串2首地址
返回值:
相等:0
大于:>0
小于:<0
*/
int strcmp(const char *s1, const char *s2);
/*
功能:比较 s1 和 s2 前n个字符的大小,比较的是字符ASCII码大小。
参数:
s1:字符串1首地址
s2:字符串2首地址
n:指定比较字符串的数量
返回值:
相等:0
大于: > 0
小于: < 0
*/
int strncmp(const char *s1, const char *s2, size_t n);
**strcmp函数,**比较两个字符串的大小,该函数的比较是以ASCII 码表上的顺序来决定。比较时,直到遇到不相同的字符或者’\0’,返回结果,根据返回结果来判断两个字符串是否相同。
char arr1[] = "hello";
char arr2[] = "world";
int res = strcmp(arr1, arr2);
if(!res){
printf("equal\n");
}
else{
printf("not equal\n");
}
**strncmp函数,**比较两个字符串的前n个字符,和strcmp的比较规则相同。
char arr1[] = "hello";
char arr2[] = "hello";
int res = strncmp(arr1, arr2, 2);
printf("%d\n", res);
strcmp和strncmp函数,在比较的时候,如果两个字符串长度相同,那么逐个字符的比较大小;如果字符串长度不同,在’\0’前,逐字符比较,遇到不同的直接返回结果;如果比较遇到’\0’还没有比较出结果,那么长的字符串大于短字符串。
char arr1[] = "hell";
char arr2[] = "hello";
char arr3[] = "helly";
char arr4[] = "hew";
int res1 = strcmp(arr1, arr2);
int res2 = strcmp(arr2, arr3);
int res3 = strcmp(arr3, arr4);
printf("%d\n", res1);
printf("%d\n", res2);
printf("%d\n", res3);
sprintff和sscanf函数
/*
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到str指定的空间中,直到出现字符串结束符 '\0' 为止。
参数:
str:字符串首地址
format:字符串格式,用法和printf()一样
返回值:
成功:实际格式化的字符个数
失败: - 1
*/
int sprintf(char *str, const char *format [, argument, ...]);
/*
功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。
参数:
str:指定的字符串首地址
format:字符串格式,用法和scanf()一样
返回值:
成功:参数数目,成功转换的值的个数
失败: - 1
*/
int sscanf(const char *str, const char *format [, argument, ...]);
**sprintf函数,**将格式化的数据写入字符串。sprintf()会根据参数format,来转换并格式化数据,然后将结果复制到参数str 所指的字符串数组,直到出现字符串结束(’\0’)为止。
int a = 123;
char s[10];
char arr[] = "hello";
sprintf(s, "%d", a);
printf("%s\n", s);
sprintf(s, "%s%d", arr, a);
printf("%s\n", s);
sprintf与printf函数的区别:二者功能相似,但是sprintf函数打印到字符串中,而printf函数打印输出到屏幕上。
**sscanf函数,**从字符串中读取指定格式的数据。将参数str的字符串根据参数format字符串来转换并格式化数据。
char src1[10] = "123";
char src2[10] = "hello 123";
char str[10];
int a = 0;
sscanf(src1, "%d", &a);
printf("%d\n", a);
sscanf(src2, "%s %d", str, &a);
printf("%s\n", str);
printf("%d\n", a);
sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。
strchr和strstr函数
/*
功能:在字符串s中查找字母c出现的位置
参数:
s:字符串首地址
c:匹配字母(字符)
返回值:
成功:返回第一次出现的c地址
失败:NULL
*/
char *strchr(const char *s, int c);
/*
功能:在字符串haystack中查找字符串needle出现的位置
参数:
haystack:源字符串首地址
needle:匹配字符串首地址
返回值:
成功:返回第一次出现的needle地址
失败:NULL
*/
char *strstr(const char *haystack, const char *needle);
strchr和strstr函数,前者时查找一个字符在目标字符串中出现的位置,后者是查找一个字符串在目标字符串中出现的位置,两个函数都是返回第一次匹配后的地址,后面如有重复将不会继续查找。c
char s[] = "hello 111123";
char c = 'l';
char str[] = "11";
char* ptrc = strchr(s, c);
char* ptrs = strstr(s, str);
printf("%s\n", ptrc);
printf("%s\n", ptrs);
strtok函数
/*
功能:来将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时, 则会将该字符改为\0 字符,当连续出现多个时只替换第一个为\0。
参数:
str:指向欲分割的字符串
delim:为分割字符串中包含的所有字符
返回值:
成功:分割后字符串首地址
失败:NULL
*/
char *strtok(char *str, const char *delim);
strtok()用来将字符串分割成一个个片段。参数str指向将要分割的字符串,参数delim 则为分割字符串,当strtok()在参数str的字符串中发现到参数delim 的分割字符时则会将该字符改为\0 字符(即,strtok函数会修改str字符串)。在第一次调用时,strtok()中的参数str指向要分解的字符串,往后的调用则将参数str设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
char str[] = "www.swu.edu.cn";
int i=0;
char* p = strtok(str, ".");
while(p != NULL){
printf("%s\n", p);
p = strtok(NULL, ".");
}
for(i=0; i<sizeof(str); i++){c
printf("%c", str[i]);
}
printf("\n");
通过上面的代码可以看出,str在每次分割后,其中的’.‘字符被替换成’\0’;每一次调用strtok函数,会以第一次查找到的’.'进行分割,并当前分割后的字符串指针。
atoi函数
/*
功能:atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或字符串结束符('\0')才结束转换,并将结果返回返回值。
参数:
nptr:待转换的字符串
返回值:成功转换后整数
*/
int atoi(const char *nptr);
atoi就是把nptr字符串转化为整数,类似的还有atol,atof函数。需要注意的是,参数nptr前面可以包含空格,但是不能包括字母,如果数字后面有字母可以把字母前的数字进行转化。
char s1[] = "100";
char s2[] = " 100";
char s3[] = " 100h100";
char s4[] = "123.456";
int num1 = atoi(s1);
int num2 = atoi(s2);
int num3 = atoi(s3);
int num4 = atoi(s4);
long num5 = atol(s1);
float num6 = atof(s4);
printf("%d\n", num1);
printf("%d\n", num2);
printf("%d\n", num3);
printf("%d\n", num4);
printf("%ld\n", num5);
printf("%f\n", num6);