求字符串长度
1.strlen
函数介绍
size_t strlen ( const char * str );
-
字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
-
参数指向的字符串必须要以 ‘\0’ 结束。
-
注意函数的返回值为size_t,是无符号的( 易错点 )
-
学会strlen函数的模拟实现。
函数的模拟实现
1.计数器的方法
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
size_t count = 0;
// 如果传递进来的地址为空,那么就会报错
assert(str);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
size_t n = my_strlen(arr);
printf("%u\n", n); // %u 打印无符号整型
return 0;
}
2.(指针 - 指针)的方法
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
char* start = str;
while(*str != '\0')
{
str++;
}
return (str-start);
}
int main()
{
char arr[] = "abcdef";
size_t len = my_strlen(arr);
printf("%u\n", len); // %u 打印无符号整型
return 0;
}
3.递归的方式
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
if (*str != '\0')
{
// str + 1 是str指向的字符串的第二个字符的地址
return 1 + my_strlen(str + 1);
}
else
{
return 0;
}
}
int main()
{
char arr[] = "abcdef";
size_t len = my_strlen(arr);
printf("%u\n", len); // %u 打印无符号整型
return 0;
}
2.strcpy
函数介绍
char* strcpy(char * destination, const char* source);
-
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
将source指向的C字符串复制到destination指向的数组中,包括结束的null字符(并在该点停止)。
-
原字符串必须以 ‘\0’ 结束。
-
会将原字符串中的 ‘\0’ 拷贝到目标空间。
-
目标空间必须足够大,以确保能存放源字符串。
-
目标空间必须可变。
-
学会模拟实现。
函数的模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
// 两个地址都不可以为空,否则就会报错
assert(dest && src);
char* ret = dest;
// 当*str 为'\0'时,赋值给*dest;则表达式结果为假,跳出循环
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[20] = {0};
// 将arr1中的字符串拷贝到arr2中
my_strcpy(arr2, arr1);
printf("%s\n", arr2);//abcdef
return 0;
}
3.strcat(catch)字符串追加
函数介绍
char * strcat ( char * destination, const char * source );
-
Appends(附加,增加) a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included
at the end of the new string formed by the concatenation (连接,串联)of both in destination.
将源字符串的副本追加(附加,增加)到目标字符串。destination中的结束null字符将被source的第一个字符覆盖,并且在destination中两个字符的连接(连接,串联)形成的新字符串的末尾包含一个空字符。
-
源字符串必须以 ‘\0’ 结束。
-
目标空间必须有足够的大,能容纳下源字符串的内容。
-
目标空间必须可修改。
-
字符串自己给自己追加,如何?
函数的模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 找到目标空间的末尾\0
while (*dest != '\0')
{
dest++;
}
//2. 拷贝字符串
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
my_strcat(arr1, "world");
printf("%s\n", arr1);
return 0;
}
- 通过对strcat函数的模拟我们可以得出结论:字符串不能自己给自己追加
由于destination中的结束空字符将被source的第一个字符覆盖,所以导致source中的结构被破坏,再拷贝的过程中找不到’\0’.
4.strcmp
函数介绍
int strcmp ( const char * str1, const char * str2 );
-
This function starts comparing the first character of each string. If they are equal to each
other, it continues with the following pairs until the characters differ or until a terminating
null-character is reached.
这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行以下对,直到字符不同或达到终止空字符为止。
-
标准规定:
-
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
-
函数的模拟实现
#include<stdio.h>
#include<assert.h>
// 方法1
int my_strcmp1(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1==*str2)
{
if (*str1 == '\0')
return 0;//相等
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
// 方法2
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;//相等
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
char arr1[20] = "zhangsan";
char arr2[] = "zhangsanfeng";
int ret = my_strcmp(arr1, arr2);
if (ret < 0)
printf("<\n");
else if (ret == 0)
printf("==\n");
else
printf(">\n");
return 0;
}
1.strncpy
函数介绍
char * strncpy ( char * destination, const char * source, size_t num );
-
Copies the first num characters of source to destination. If the end of the source C string
(which is signaled by a null-character) is found before num characters have been copied,
destination is padded(v.填充) with zeros until a total of num characters have been written to it.
将source的前num个字符复制到目标。如果在复制num个字符之前,找到source C字符串的结尾(由空字符表示),则用零填充目标(v.填充),直到向其写入总数为num个字符。
-
拷贝num个字符从源字符串到目标空间。
-
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
strncpy
函数用于将一个字符串的一部分复制到另一个字符串中,并在必要时添加 null 终止符。以下是 strncpy
函数的简单模拟实现:
#include <stdio.h>
char* strncpy_custom(char* dest, const char* src, size_t n) {
char* ptr = dest; // 保存目标字符串的起始地址
// 将源字符串的内容逐个复制到目标字符串中,直到达到指定的长度 n 或者遇到 '\0'
while (*src != '\0' && n > 0) {
*dest++ = *src++;
n--;
}
// 如果已经复制完源字符串的内容,但目标字符串还有剩余空间,则在目标字符串的末尾添加 '\0'
while (n > 0) {
*dest++ = '\0';
n--;
}
return ptr; // 返回目标字符串的起始地址
}
int main() {
char src[] = "Hello, world!";
char dest[20]; // 目标字符串的长度为 20
// 使用自定义的 strncpy_custom 函数将 src 字符串的内容复制到 dest 字符串中
strncpy_custom(dest, src, 5); // 复制前5个字符
printf("Copied string: %s\n", dest); // 输出结果为 "Hello"
return 0;
}
这个自定义的 strncpy_custom
函数遵循了 strncpy
函数的基本原理,逐个复制源字符串的字符到目标字符串中,直到达到指定的长度 n
或者遇到源字符串的结束符 \0
。然后,如果目标字符串的长度还有剩余空间,会在目标字符串的末尾添加 \0
终止符。
2.strncat
- 函数介绍
char * strncat ( char * destination, const char * source, size_t num );
-
Appends(附加,增加) the first num characters of source to destination, plus a terminating
null-character.
向目标追加(附加,增加)源的前num字符,加上一个结束的空字符。
-
If the length of the C string in source is less than num, only the content up to the terminating
null-character is copied.
如果source中的C字符串的长度小于num,则只复制结束空字符之前的内容。
下面是模拟实现 strncat
函数的示例代码:
#include <stdio.h>
// 自定义的 strncat 函数,将源字符串的前 n 个字符拼接到目标字符串的末尾
char* strncat_custom(char* dest, const char* src, size_t n) {
char* ptr = dest; // 保存目标字符串的起始地址
// 遍历到目标字符串的末尾
while (*dest != '\0') {
dest++;
}
// 将源字符串的前 n 个字符逐个拼接到目标字符串的末尾
while (*src != '\0' && n > 0) {
*dest++ = *src++;
n--;
}
*dest = '\0'; // 在拼接完成后添加字符串终止符
return ptr; // 返回目标字符串的起始地址
}
int main() {
char dest[20] = "Hello, ";
char src[] = "world!";
// 使用自定义的 strncat_custom 函数将 src 字符串的内容拼接到 dest 字符串的末尾
strncat_custom(dest, src, 3); // 拼接 src 字符串的前3个字符
printf("Concatenated string: %s\n", dest); // 输出结果为 "Hello, wor"
return 0;
}
这个自定义的 strncat_custom
函数首先将指针移动到目标字符串的末尾,然后将源字符串的前 n 个字符逐个拼接到目标字符串的末尾,最后在拼接完成后添加字符串终止符。
3.strncmp
- 函数介绍
int strncmp ( const char * str1, const char * str2, size_t num );
-
Compares up to num characters of the C string str1 to those of the C string str2.
This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ, until a terminating null-character is reached, or until num characters match in both strings, whichever happens first.比较C字符串str1和C字符串str2最多num个字符。这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续下面的对,直到字符不相同,直到达到终止的空字符,或者直到两个字符串中的num字符匹配,以先发生的为准。
-
Returns an integral value indicating the relationship between the strings:
返回一个整数值,指示字符串之间的关系:
字符串查找
1.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.
返回指向str1中str2第一次出现的指针,如果str2不是str1的一部分,则返回空指针。
函数的模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = str1;
const char* p = str1;
const char* s2 = str2;
while (*p)
{
s1 = p;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
// 此时p指向的字符,就是str1中str2第一次出现的指针
return (char*)p; //由于返回类型为char*,p为const char*,因此需要强转类型
}
p++;
}
// str2 不存在于 str1中
return 0;
}
int main()
{
char arr1[] = "abbbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
2.strtok(token)
token n. 标记,标志,符号,记号
函数介绍
char * strtok ( char * str, const char * sep );
-
sep参数是个字符串,定义了用作分隔符的字符集合
-
第一个参数指定一个字符串,这个字符串包含了(0个或者多个由sep字符串中一个或者多个分隔符)分割的标记。
-
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
-
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它(标记)在字符串
中的位置
-
strtok函数的第一个参数为 NULL ,函数将(在同一个字符串中)被保存的位置开始,查找下一个标
记。
-
如果字符串中不存在更多的标记,则返回 NULL 指针。
// 方法一
int main()
{
const char* sep = "@.";
char email[] = "doupocangqiong@xiaoyan.com.net";
char cp[40] = { 0 }; //"doupocangqiong@xiaoyan.com.net"
strcpy(cp, email);
// 分隔符可以使@. 也可以是@ 或者 .
char* ret = strtok(cp, sep);
if(ret != NULL)
printf("%s\n", ret);
ret = strtok(NULL, sep);
if (ret != NULL)
printf("%s\n", ret);
ret = strtok(NULL, sep);
if (ret != NULL)
printf("%s\n", ret);
ret = strtok(NULL, sep);
if (ret != NULL)
printf("%s\n", ret);
return 0;
}
// 方法二
int main()
{
const char* sep = "@.";
char email[] = "doupocangqiong@xiaoyan.com.net";
char cp[40] = { 0 };//"doupocangqiong@xiaoyan.com.net"
strcpy(cp, email);
char* ret = NULL;
for (ret = strtok(cp, sep);
ret != NULL;
ret = strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
错误信息报告
1.strerror
函数介绍
char * strerror ( int errnum );
- 返回错误码,所对应的错误信息。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <errno.h>
int main()
{
//printf("%s\n", strerror(0));
//printf("%s\n", strerror(1));
//printf("%s\n", strerror(2));
//printf("%s\n", strerror(3));
//printf("%s\n", strerror(4));
//printf("%s\n", strerror(5));
// errno - C语言设置的一个全局的错误码存放的变量
// 如果返回空指针,会将错误码存放到errno
FILE* pf = fopen("C:\\Users\\qwy\\Desktop\\test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
else
{
//
}
return 0;
}
内存操作函数
1. memcpy(memory)
函数介绍
内存拷贝:可以拷贝任意类型的数据
void * memcpy ( void * destination, const void * source, size_t num );
-
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
-
这个函数在遇到 ‘\0’ 的时候并不会停下来。
-
如果source和destination有任何的重叠,复制的结果都是未定义的。
-
(memcpy) 负责拷贝两块独立空间中的数据)
函数的模拟实现
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
//void* 类型不能够被解引用;强转为char* 方便拿到每一个内存单元的数据
dest = (char*)dest + 1;
// 将dest强转为char* 类型;则(+1)每次跳过1byte
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 28); //从arr1 拷贝28byte 到 arr2
return 0;
}
2. memmove
函数介绍
void * memmove ( void * destination, const void * source, size_t num );
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
函数的模拟实现
- 纠正:当
dest
在区间1,src
在区间2,此时是dest < src
, 此时必须从前向后打印
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest < src)
{
//前->后(从前往后拷贝)
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后->前(从后往前拷贝)
while (num--)
{
*((char*)dest+num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1+5, arr1+6, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
3. memcmp
- 函数介绍
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
-
比较从
ptr1
和ptr2
指针开始的num
个字节 -
返回值如下:
int main()
{
int arr1[] = { 1,2,3,4,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00
int arr2[] = { 1,3,2 };
//01 00 00 00 03 00 00 00 02 00 00 00
int ret = memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
4.memset
函数介绍
void * memset ( void * ptr, int value, size_t num )
-
Fill block of memory
Sets the first num bytes of the block of memory pointed by ptr to the specified(具体的,详细的) value ,(interpreted(解释,说明,口译) as an
unsigned char
).将ptr指向的内存块的前num个字节设置为指定值,解释为unsigned char。
-
ptr
Pointer to the block of memory to fill.
指向要填充的内存块的指针。
-
value
Value to be set. The value is passed as an
int
, but the function fills the block of memory using the unsigned char conversion (转换,转变)of this value.需要设置的值。该值作为' int '传递,但函数使用该值的unsigned char转换来填充内存块。
-
num
Number of bytes to be set to the value. size_t is an unsigned integral type.
要设置为该值的字节数。Size_t是一个无符号整型。
-
Return Value
ptr is returned.
int main()
{
//case 1:
//char arr[] = "hello ljl";
//memset(arr, 'x', 5);
//memset(arr+6, 'x', 3);
//printf("%s\n", arr);
//case 2:
int arr[10] = { 0 };
// 把arr初始化为全1(err)
// 只是将前40个字节全部初试化为1,并不是将整个数组初始化为1
memset(arr, 1, 40);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
// 01 01 01 01 将16进制转化为10进制就是 16,843,009
return 0;
}
nt`, but the function fills the block of memory using the unsigned char conversion (转换,转变)of this value.
需要设置的值。该值作为' int '传递,但函数使用该值的unsigned char转换来填充内存块。
-
num
Number of bytes to be set to the value. size_t is an unsigned integral type.
要设置为该值的字节数。Size_t是一个无符号整型。
-
Return Value
ptr is returned.
int main()
{
//case 1:
//char arr[] = "hello ljl";
//memset(arr, 'x', 5);
//memset(arr+6, 'x', 3);
//printf("%s\n", arr);
//case 2:
int arr[10] = { 0 };
// 把arr初始化为全1(err)
// 只是将前40个字节全部初试化为1,并不是将整个数组初始化为1
memset(arr, 1, 40);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
// 01 01 01 01 将16进制转化为10进制就是 16,843,009
return 0;
}