大家好哇!好久不见!这里是菜菜!
首先祝大家暑假快乐喔!
今天我们来了解了解字符串函数和内存函数。
目录
(一)字符串函数
在C语言里有许多的字符串函数,我们今天就先说说那些常用的字符串函数:
下面我们就将上面的字符串函数展开讲讲:
(1)strlen
size_t strlen ( const char * str );
strlen函数是返回从字符串中'\0'前面至某个内存位置出现的字符个数。(注:统计的字符个数不包括'\0')
我们观察strlen函数,它返回值类型为size_t(unsigned int),接收的参数为是个地址。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc\0def";
printf("%zu\n", strlen(arr1));
printf("%zu\n", strlen(arr2));
printf("%zd\n", sizeof(arr1));
printf("%zd\n", sizeof(arr2));
return 0;
}
运行结果:
在这里我们能看到数组arr1的是 6,但是字符串arr1的sizeof操作是 7,这说明我们在完成对字符串初始化后,系统会自动帮我们追加一个 '\0'(下面不再进行赘述)。同时,对比字符串arr1,字符串arr2在中间有一个字符'\0',相应的在调用函数strlen时,函数遇到'\0'字符时就会直接返回统计的字符个数,故返回为 3,但在sizeof操作里,因为字符串中间多了一个字符'\0',故大小为 8。
(2)strcpy
char* strcpy(char * destination, const char * source);
strcpy函数遇见源字符串的 '\0'就会停止,但是strcpy函数会把 '\0'拷贝至目标字符串,因此目标空间必须足够大,确保能放源字符串。
这里我们能看到 strcpy 函数的返回的是 char* 类型,即返回一个地址。接收的参数为两个地址,其中第二个地址用 const 修饰,表示指针 source 可以改变指向,但是其指向的值不可改变。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcde";
char arr2[] = "xxxxxxxxxxxxx";
printf("%s\n", arr2);
strcpy(arr2, arr1); //将字符数组arr1拷贝至字符数组arr2中
printf("%s\n", arr2);
return 0;
}
运行结果:
在这里我们的字符串 arr2 的大小明显大于arr1,并且我们在调用 strcpy函数 以后输出,并没有将后续的字符 'x' 打印输出,说明在调用函数时,把 字符串arr1 中的字符 '\0'也拷贝至 字符串arr2中,我们也可以打开调试查看 字符串arr2 中的字符。
(3)strcat
char * strcat ( char * destination, const char * source );
strcat函数将源字符串追加至目标,遇见源字符串的 '\0'就会停止,目标空间需要足够大,确保能够放下源字符串。
这里我们能看到的 strcat函数 返回类型为 char* ,即返回一个地址。接收的参数为两个地址,其中第二个地址用 const 修饰,表示指针 source 可以改变指向,但是其指向的值不可改变。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "defg";
char arr2[10] = "abc";
strcat(arr2, arr1); //将字符数组arr1追加至字符数组arr2中
printf("%s\n", arr2);
return 0;
}
运行结果:
这里是把 字符串arr1 追加至 字符串arr2 中,再对 字符串arr2进行输出,即得到结果。在追加字符串时,仍然会把 字符'\0'追加至目标字符串中。
我们需要注意的是,strcat函数并不能追加自身字符串,因为 strcat函数 是遇见源字符串的 '\0' 才会停止,但是在自身追加过程中,目标字符串的'\0' 会被覆盖掉,又因为是自身追加,故源字符串的 '\0' 也被修改掉,从而使得strcat函数无法停止。
(4)strcmp
int strcmp ( const char * str1, const char * str2 );
strcmp是比较字符串的函数:
比较原则:第一个字符串大于第二个字符串,则返回大于0的数字;第一个字符串等于第二个字符串,则返回0;第一个字符串小于第二个字符串,则返回小于0的数字。一般 strcmp函数 是用来判断两字符串是否相等。
strcmp返回值是一个整形,而接受的参数是两个char* 的地址,因为不需要对传入的字符串进行修改,故使用const修饰。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcd";
char arr2[] = "abca";
char arr3[] = "abcd";
printf("%d\n", strcmp(arr1, arr2)); //字符数组arr1与arr2进行比较
printf("%d\n", strcmp(arr1, arr3)); //字符数组arr1与arr3进行比较
return 0;
}
运行结果:
首先,将 字符串arr1 与 字符串arr2 进行比较:将两个字符串的每个字符进行,因为字符在计算机内存储的是其ASCLL码,故直接比较其ASCLL值即可得出结果,当比较字符 'd' 与 'a' 时,因为字符 'd' 的ASCLL值大于 字符 'a',故strcmp函数返回值为1;当比较 字符串arr1 和 字符串arr3 时,因为两字符串内所有字符相等,故返回值为0。(strcmp函数并不能比较字符串的长度,而是比较其内字符的ASCLL码值)
(5)strstr
char * strstr ( const char *str1, const char * str2);
strstr是查找字符串内是否存在目标字串,如果存在,则返回目标字串的地址,否则返回NULL。
strstr函数返回的是 char* 类型的地址,接收的是两个 char* 类型的地址。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdefgh";
printf("%s\n", strstr(arr, "bcde"));
printf("%s\n", strstr(arr, "bcad"));
return 0;
}
运行结果:
因为strstr返回的是 char* 类型的地址,故在第一个输出中,因为 字符串arr 内存在 子串"bcde" ,故 strstr函数 返回的是其子串的地址,即 'b' 的地址;在第二个输出中,因为 字符串arr 不存在子串 "bcad" 故返回为NULL。
(6)strtok
char * strtok ( char * str, const char * sep );
strtok函数 是用来截断字符串的,其中 str 是用来接收字符串的地址的, sep 是用来接收字符串截断标志(集合)的,strtok返回的是char* 类型的地址。strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(strtok函数会改变被接收字符串),strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。 如果字符串中不存在更多的标记,则返回 NULL 指针。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "https://blog.csdn.net";
printf("%s\n", strtok(arr, "://."));
printf("%s\n", strtok(NULL, "://."));
printf("%s\n", strtok(NULL, "://."));
printf("%s\n", strtok(NULL, "://."));
return 0;
}
运行结果:
首先第一个输出里,调用strtok函数,其在传入的字符串中寻找截断字符标志,找到后将其修改为 '\0',再返回截断字符标志前的字符串的地址,在第二个输出里,调用strtok函数,因为接收的地址为NULL,所以strtok函数会从上一次修改的位置继续向后寻找,直至找到下一个阶段字符标志。如果相邻两截断字符标志内无字符串,则会跳过继续向后寻找。下面我们打开调试观察截断后字符串arr内的内容。
(7)strerror
char * strerror ( int errnum );
返回错误码,所对应的错误信息。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <errno.h> //头文件
int main()
{
FILE* fp = fopen("test.txt", "r"); //文件指针打开文件
printf("%s\n", strerror(errno)); //输出错误码对应的错误信息
return 0;
}
运行结果:
打开文件失败,打印其错误信息。
(二)内存函数
(1)memset
void *memset( void *dest, int c, size_t count );
memset函数是将地址dest起的第count个字节全部赋值为c。
memset函数接收的是一个void * 地址,其是为了能够接收多种地址类型(下面不再进行赘述),另外接收的参数为size_t类型的值,用来记录赋值的字节数,而另一个参数c则是将赋值的内容。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr[10] = { 0 };
memset(arr, 'M', 9); //自地址arr起的9个字节全部赋值为字符'M'
printf("%s\n", arr);
return 0;
}
运行结果:
memset函数将自arr地址起的9个字节全部赋值为'M'。从结果上看,数组arr内确实赋值为'M',只选9个字节是因为需要留一个字符'\0'用于输出。
(2)memcpy
void * memcpy ( void * destination, const void * source, size_t num );
memcpy是用于内存拷贝,作用范围比 strcpy函数 更广一些。
memcpy接收的参数是两个 void* 类型的地址,另一个参数为size_t类型,即需要拷贝字节数。函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。 这个函数在遇到 '\0' 的时候并不会停下来。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Peo //定义一个结构体
{
char name[10];
int age;
}A, B;
int main()
{ //初始化
char arr[] = "caicai";
A.age = 20;
memcpy(&A.name, arr, sizeof(arr)); //将字符串arr拷贝至结构体A的name里
memcpy(&B, &A, sizeof(A)); //将结构体B内存拷贝至结构体A中
printf("%s\n%d", B.name, B.age);
return 0;
}
运行结果:
首先定义一个结构体,再初始化一个字符数组,将字符数组内存拷贝至结构体A的name中,将A中的age赋值为20,再将结构体A内存拷贝至结构体B中。
(3)memmove
void * memmove ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
memmove接收的参数为两个void* 类型的地址,另一个参数为size_t类型,即需要拷贝字节数。如果源空间和目标空间出现重叠,就得使用memmove函数处理。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 2, arr, 20); //从数组arr中,自地址arr开始拷贝20个字节(5个整形元素)至arr+2出
for (int i = 0; i < 10; i++) //循环输出数组元素
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果:
因为 memmove(arr+2,arr,20),故从arr开始的20个字节拷贝至从arr+2的地址处的20个字节,20个字节即对应5个整形大小,故数组内元素为: 1 2 1 2 3 4 5 8 9 10.
(4)memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比较从ptr1和ptr2指针开始的num个字节。
memcmp接收两个地址,再从两个地址开始比较num个字节。该函数返回值意义与上述strcmp类型,这里不再进行赘述。
例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[10] = { 1,2,3,4,5 };
int arr2[10] = { 1,2,3,3,4 };
printf("%d\n", memcmp(arr1, arr2, 12)); //比较数组arr1和数组arr2的前12个字节,即前3个元素
printf("%d\n", memcmp(arr1, arr2, 16)); //比较数组arr1和数组arr2的前16个字节,即前4个元素
return 0;
}
运行结果:
第一个输出中,比较数组arr1和数组arr2的前12个字节,即前3个元素,因为两个数组前3个元素相等,故返回打印0;第二个输出中,比较数组arr1和数组arr2的前16个字节,即前4个元素,因为两个数组前4个元素不相等,数组arr2的第4个元素小于数组arr1的第4个元素,故返回打印1;
今天就分享到这里了!
您的点赞与关注是对菜菜最大的支持!