一.相关函数分类
1.求字符串长度
strlen
2.长度不受限制的字符串函数
strcpy strcat strcmp
3.长度受限制的字符串函数介绍
strncpy strncat strncmp
4.字符串查找
strstr strtok
5.错误信息报告
strerror
前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量 适用于那些对它不做修改的字符串函数.
二. 函数介绍
2.1 strlen 长度计算
1.字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
#include <stdio.h>
include <string.h>
int main(){
char arr[]="abcdef";//abcdef\0
int len=strlen(arr);
printf("%d",len);
return 0;
}
结果:6
2.参数指向的字符串必须要以 '\0' 结束。
#include <stdio.h>
include <string.h>
int main(){
char arr[]={'b','i','t'};//
int len=strlen(arr);
printf("%d",len);
return 0;
}
运行结果为随机值
3.注意函数的返回值为size_t,是无符号的( 易错 )
//size_t strlen ( const char * str );C
//size_t 为无符号整型
#include <stdio.h>
#include <string.h>
int main(){
const char*str1 = "abcdef";
const char*str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
运行结果:str2>str1
strlen返回的是无符号整型,两个无符号整型 运算结果还是无符号整型,尽管相减是-3,但是当做无符号整型处理,存到内存的补码将会当成正数。可以直接进行比较或者强制转换类型。
学会strlen函数的模拟实现
计数器
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define N 100
int my_strlen(const char *str)
{
int count = 0;
assert(str);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[N] = {0};
printf("输入字符串:\n");
scanf("%s", arr);
int n = my_strlen(arr);
printf("%d\n", n);
return 0;
}
int main(){
char ch[N];
//printf("请输入字符串:\n");
gets(ch);
printf("%d\n",mystrlen(ch));
return 0;
}
int mystrlen(const char str[ ])
{
int i ;
int len = 0; //计数器置0
for (i=0; str[i]!='\0'; i++) {
len++;
}
return len;
}
指针-指针(也可计算长度)
#include <stdio.h>
#define N 100
int my_strlen(char *s)
{
char *p = s;
while (*p != '\0')
p++;
return p - s;
}
int main()
{
char str[N] ={0};
scanf ("%s",str);
int length = my_strlen(str);
printf("字符串长度:%d\n", length);
return 0;
}
补充知识:assert断言
assert
是C语言中的一个宏定义,用于在程序中进行断言(assertion)。它的作用是在代码中插入一条断言条件,用于检查某个表达式的结果是否为真。如果断言条件为假,即表达式结果为0,则会触发断言错误。
assert
宏的语法如下:
#include <assert.h> void assert(int expression);
其中,expression
是一个要进行断言的条件表达式,通常是一个返回布尔值的表达式。如果expression
为假(即0),assert
宏会触发断言错误。
断言错误的输出通常包含了触发断言的源文件、行号以及一条错误消息。断言错误通常会导致程序终止执行,以帮助开发者快速发现并定位问题。
assert
的主要用途是在开发和调试阶段进行错误处理和调试信息的输出。通过合理地使用断言,我们可以在代码中插入一些逻辑检查点,确保程序在正确的条件下执行,同时帮助发现和修复潜在的问题。
需要注意的是,断言通常在开发过程中使用,在发布版本中会被禁用。这是因为断言仅用于开发和调试,而不应该成为生产代码中的错误处理机制。
示例用法:
#include <stdio.h>
#include <assert.h>
int main() {
int x = 10;
assert(x > 0); // 断言x大于0
printf("断言通过\n");
int y = 0;
assert(y != 0); // 断言y不等于0
printf("这行代码不会被执行\n");
return 0;
}
在上述示例中,第一个断言 assert(x > 0);
是正确的,因此程序会输出 "断言通过"。而第二个断言 assert(y != 0);
是错误的,因为y等于0,所以会触发断言错误,并终止程序的执行。
2.2 strcpy 拷贝
Copies the C string pointed by source into the array pointed by destination, including the
terminating null character (and stopping at that point).
源字符串必须以 '\0' 结束。会将源字符串中的 '\0' 拷贝到目标空间。目标空间必须足够大,以确保能存放源字符串。目标空间必须可变。
学会模拟实现。
char* strcpy(char * destination, const char * source );
错误用法
int main(){
const char*p="abcdef";
char arr[]="bit";
strcpy(p,arr);//error 目标区域不可修改,常量字符串
return 0;
}
模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* p1, const char* p2) {
assert(p1); //如果为空指针,则报错
assert(p2);
char* ret = p1;
while ((*p1++ = *p2++)) {
}
return ret;
}
int main() {
char arr1[100] = {0};
char arr2[100] = {0}; // 修改为合适的大小,以避免缓冲区溢出
printf("输入字符串:");
scanf("%s", arr2);
my_strcpy(arr1, arr2);
printf("%s\n", arr1); // 打印复制后的字符串
return 0;
}
2.3 strcat 字符串追加
char* strcat(char * destination, const char * source );
源字符串必须以 '\0' 结束。目标空间必须有足够的大,能容纳下源字符串的内容。目标空间必须可修改。
字符串自己给自己追加,如何?不能,会破坏原字符串。
模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
char *my_strcat(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
//寻找\0
while(*dest)//while(*dest !='\0')
{
dest++;
}
while((*dest++ = *src++)){
;
}
return ret;
}
int main(){
char arr1[]="I love ";
char arr2[100]={0};
scanf("%s",arr2);
my_strcat(arr1, arr2);
printf("%s\n", arr1); // 打印追加后的字符串
return 0;
}
2.4 strcmp 字符串比较
字符串的字典序比较是指按照字典(词典)的排序方式来比较字符串的大小。在字典序中,字符串按照字符的 ASCII 值的顺序进行比较。
具体来说,对于两个字符串进行字典序比较时,从左到右逐个比较对应位置上的字符的 ASCII 值。如果两个字符相同,则继续向后比较下一个字符,直到遇到不同的字符,或者至少其中一个字符串结束。
int strcmp ( const char * str1, const char * str2 );
标准规定
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
那么如何判断两个字符串?
模拟实现
#include <stdio.h>
#include <string.h>
//#include <assert.h>
int my_strcmp(char *str1, char*str2){
while(*str1==*str2){
if(*str1=='\0')
return 0;
str1++;
str2++;
}
if (*str1>*str2) //这几行也可以直接替换成 return(*str1-*str2);
return 1;
else
return -1;
}
int main(){
char str1[100]={0};
char str2[100]={0};
printf("请输入字符串\n");
scanf("%s",str1);
scanf("%s",str2);
int ret=my_strcmp(str1,str2);
if (ret==0)
printf("=\n");
else if(ret>0)
printf(">\n");
else
printf("<");
return 0;
}
以下三个函数第三个参数控制了字符个数
2.5 strncpy
char * strncpy ( char * destination, const char * source, size_t num );
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加\0,直到num个。
#include <stdio.h>
#include <string.h>
int main(){
char dest[20] = "Hello";
char src[] = " World";
strncat(dest, src, 6);
printf("%s", dest); // Output: Hello World
return 0;
}
2.6 strncat
追加num个字符从源字符串到目标空间。
char * strncat ( char * destination, const char * source, size_t num );
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[20];
char str2[20];
strcpy (str1,"To be ");
strcpy (str2,"or not to be");
strncat (str1, str2, 6);
//puts (str1);
printf ("%s\n",str1);
return 0;
}
运行结果:To be or not
2.7 strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
#include <stdio.h>
int main(){
char str1[] = "Hello";
char str2[] = "Hell";
int result = strncmp(str1, str2, 4);
if (result == 0) {
printf("Strings are equal");
} else if (result < 0) {
printf("str1 is less than str2");
} else {
printf("str1 is greater than str2");
}
return 0;
}
//运行结果:Strings are equal
-
注意事项
-
num
参数指定要比较的字符数,如果两个字符串的前n个字符完全相等,则返回0。 -
如果要比较的字符数大于字符串的长度,则会比较整个字符串。
-
知识补充
在C语言中,空字符是指ASCII码为0的字符,它表示字符串的结束。在字符串中,空字符(\0
)用于标记字符串的结束,因此也被称为字符串结束符。
2.8 strstr 字符串查找
char * strstr ( const char * str1, const char * str2);
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.(函数返回字符串str2在字符串str1中第⼀次出现的位置)。The matching process does not include the terminating null-characters, but it stops there.(字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志)。
函数实现
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="This is a simple string";
char * pch;
pch = strstr (str,"simple");
printf("%s\n", pch);
return 0;
}
//运行结果: simple string
模拟实现(暴力模拟)
1.一次匹配就成功 2.多次匹配 3.没有找到
需要指针记录开始匹配的位置,记录起始位置。
#include <stdio.h>
//#include <string.h>
char * strstr (const char * str1, const char * str2){
const char*s1=NULL;
const char*s2=NULL;
const char*cur=str1;
if(*str2=='\0'){
return (char *)str1;
}
while(*cur){
s1=cur;
s2=str2;
while(*s1!='\0' && *s2!='\0' && *s1==*s2){
s1++;
s2++;
}
if(*s2=='\0'){
return (char*)cur;
}
cur++;
}
return NULL;
}
int main(){
char str1[100];
char str2[100];
scanf("%s",str1);
scanf("%s",str2);
printf("%s\n",strstr(str1,str2));
}
2.9 strtok
char * strtok ( char * str, const char * sep);
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "192.168@6.111*98896";
char* sep = ".@*";
char* str = NULL;
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
2.10 strerror
char * strerror ( int errnum );
#include <errno.h>
#include <string.h>
#include <stdio.h>
//我们打印下0~10这些错误码对应的信息
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%d->%s\n", i,strerror(i));
}
return 0;
}
/*
0->No error
1->Operation not permitted
2->No such file or directory
3->No such process
4->Interrupted function call
5->Input/output error
6->No such device or address
7->Arg list too long
8->Exec format error
9->Bad file descriptor
10->No child processes
*/
实例
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("Error opening file unexist.ent: %s\n", strerror(errno));
return 0;
}
//运行结果:Error opening file unexist.ent: No such file or directory
知识补充
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile= fopen ("unexist.ent","r");
if (pFile == NULL)
perror("Error opening file unexist.ent");
return 0;
}
//运行结果;Error opening file unexist.ent: No such file or directory