扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
sizeof
strlen
strcpy
strncpy
strcmp
strncmp
strcat
strncat
strstr
strtok
streror
memcpy
memmove
memcmp
sizeof准确的来讲不是一个库函数,而是一个单目运算符。它的参数可以是数组、指针、类型、对象、函数等,用来计算一块内存的大小。如果是字符串,则用sizeof的时候计算结果是包含结束符‘\0’的,因为结束符也是占用空间的。
sizeof是在编译的时候就计算好了缓冲区的长度,因此不能拿来计算和返回动态分配的内存大小。
实例:
#include#includeint main()
{int s[10] = {0 };
char s1[] = "abcdef";
char s2[10] = "abcdef";
printf("%d\n", sizeof(s));//输出40
//初始化数组指定数组大小10个元素,每个元素类型是int,所以输出10*4=40
printf("%d\n", sizeof(s1));//输出7
//初始化数组时没有指定大小,实际看数组占多大内存
//abcdef占6个字节,字符串初始化数组会默认携带一个'\0',所以大小为6+1=7
printf("%d\n", sizeof(s2));//输出10;
//初始化数组时指定数组大小为10,每个元素是int,所以输出10*1=10
return 0;
}
strlen计算字符串长度。该函数返回字符串的长度,从第一个字符开始,到结束符截止,但是不包括结束符。
注意返回值是一个无符号整形数据
库函数中实现的strlen函数: size_t strlen ( const char * str );
typedef unsigned int size_t;
size_t 表示无符号的整型
实例
int main()
{char s[] = "abcdef";
int ret = strlen(s);
printf("%d", ret);//输出6
return 0;
}
模拟实现:
#include#include
//法1 遍历
size_t my_strlen1(const char* str)
{assert(*str != NULL);
int count = 0;
while (*str != '\0')
{str++;
count++;
}
return count;
}
//法2 递归
size_t my_strlen2(const char* str)
{//assert(*str != NULL);
if (*str != '\0') {return my_strlen2(str + 1) + 1;
}
else {return 0;
}
}
//法3 指针-指针
size_t my_strlen3(const char* str)
{const char* start = str;
assert(*str != '\0');
while (*str != '\0')str++;
return str - start;
}
int main()
{char s[50] = "adsljkfakdsfj";
printf("%d\n", my_strlen1(s));//输出13
printf("%d\n", my_strlen2(s));//输出13
printf("%d\n", my_strlen3(s));//输出13
return 0;
}
strcpy库函数中实现的strcpy函数: char * strcpy ( char * destination, const char * source );
opies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point)
将源指向的C字符串复制到目标指向的数组中,包括终止空字符(并在该点停止)
为避免溢出,目标指向的数组的大小应足够长,以包含与源相同的 C 字符串(包括终止空字符),并且不应在内存中与源重叠
实例:
int main()
{char s[50] = "asdfh";
char s1[20] = "dfajslk";
char* ret = strcpy(s, s1);//会返回一个地址
printf("%s", ret);//输出dfajslk
return 0;
}
模拟实现:
#include#include
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);
char* ret = dest;
while (*dest++ = *src++);
return ret;
}
//模拟实现strcpy
int main()
{char s[50] = "asdfh";
char s1[20] = "dfajslk";
char* ret = my_strcpy(s, s1);
printf("%s", ret);//输出dfajslk
return 0;
}
strncpy函数定义:char * strncpy ( char * destination, const char * source, size_t num );
将源的第一个字符数复制到目标。如果在复制 num 个字符之前找到源 C 字符串的末尾(由 null 字符表示),则目标将填充零,直到总共写入 num 个字符为止。
如果源长度超过 num,则不会在目标末尾隐式附加空字符。因此,在这种情况下,不应将目标视为以空结尾的 C 字符串(这样读取它会溢出)。
复制指针source 指向的内存中的前num个字符到指针destination指向的内存块,包括结束符。
如果num个数大于source的字符个数,则依然复制num个字符,多的那部分填充’\0’ 。
如果num个数少于source的字符的个数,则字符串destination不是以结束符结尾,此 时如果访问字符串destination可能会导致溢出,应该手动填充结束符。
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[] = "asdhkjadsg";
char s2[50];
char* ret = strncpy(s2, s1,5);
*(ret + 5) = '\0';//手动添加结束标志
printf("%s\n", ret);//输出asdhk
printf("%s\n", s2);//输出asdhk
return 0;
}
strcmp函数定义: int strcmp ( const char * str1, const char * str2 );
比较两个字符串,从字符串的首位开始比较起,如果他们相等,则依次往后,直到遇到不相同的字符,或直到结束符。如果字符串1和字符串2相等,则返回0,如果str1小于str2,则返回负数,如果str1大于str2,则返回正数。
实例:
int main()
{char s1[] = "asdfjz";
char s2[] = "asdfjh";
int ret = strcmp(s1, s2);
printf("%d", ret);//输出1
return 0;
}
模拟实现:
#include#include
//模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);
//判断首字符是否相同,若是相同进入while循环继续判断下一个
while (*str1 == *str2)
{if (*str1 == '\0')//当两个字符串遍历完仍然相同时
{ return 0;//返回0表示两个字符串相同
}
str1++; str2++;
}
//判断大小
if (*str1 >*str2)return 1;
else return -1;
}
int main()
{char s1[] = "asdfjz";
char s2[] = "asdfjh";
int ret = my_strcmp(s1, s2);
printf("%d", ret);//输出1
return 0;
}
strncmp函数声明:int strncmp ( const char * str1, const char * str2, size_t num );
将 C 字符串 str1 的字符数与 C 字符串 str2 的字符数进行比较。
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下对,直到字符不同,直到达到终止的空字符,或者直到两个字符串中的 num 字符匹配,以先发生者为准
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[] = "abcdefgg";
char s2[] = "abcdefgh";
int ret = strncmp(s1, s2,8);
if (ret >0)
{printf("s1 >s2\n");
}else if(ret==0)
{printf("s1 = s2");
}
else {printf("s1< s2");
}
return 0;//输出 s2 >s1
}
模拟实现:
#include#include#include
int my_strncmp(const char* str1, const char* str2, int num)
{assert(str1 && str2);
while (*str1 == *str2)
{while (num>0)
{ if (*str1 == *str2)//如果两个指针解引用指向的字符相同,就迭代往后走
{ str1++; str2++;
}
else {//如果碰到不同的,则返回两个字符之间的差
return *str1 - *str2;
}
num -- ;
}
if (num == 0)
{ return 0;
}
}
return *str1 - *str2;
}
int main()
{char str1[] = "abcde";
char str2[] = "abcdf";
int ret = my_strncmp(str1, str2, 4);
int ret1 = my_strncmp(str1, str2, strlen(str2));
printf("%d\n", ret);
printf("%d\n", ret1);
return 0;
}
strcat函数声明:char * strcat ( char * destination, const char * source );
连接字符串。将指针source 指向的字符串连接在指针destination指向的字符串后面,并且原来字符串的结束符会被source的首字符覆盖掉,surce的结束符也会转移过去,成为形成的新的字符串的结束符。
连接成功则返回dset的首地址,失败则返回空指针。
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[20] = "asd";
char* ret = strcat(s1, "hhl");//将字符串"hhl"追加到s1后面
if (ret != NULL)
{printf("%s\n", ret);//输出 asdhhl
}
else {printf("没有追加成功\n");
}
return 0;
}
模拟实现:
#include#include
char* my_strcat(char* dest, const char* src)
{assert(dest && src);
char* ret = dest;
//1.找到目标空间的\0
while (*dest != '\0')dest++;
//2.追加
while (*dest++ = *src++) {;
}
return ret;
}
int main()
{char s[50] = "dsal";
char s1[] = "daskf";
char* ret = my_strcat(s, s1);
printf("%s",ret);//输出dsaldaskf
return 0;
}
strncat函数声明:char * strncat ( char * destination, const char * source, size_t num );
将指针source 指向的字符串的num个连接在指针destination指向的字符串后面,并且原来字符串的结束符会被source的首字符覆盖掉,
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[20] = "adas";
char s2[] = "hh";
char* ret = strncat(s1, s2, sizeof(s2));
printf("%s", ret);//输出adashh
return 0;
}
模拟实现:
#include#include
#includechar* my_strncat(char* dest, const char* src, int size_t)
{assert(dest && src);
char* ret = dest;
while (*dest != '\0')dest++;
while (size_t-- >0)//size_t=3
{if (*src == '\0') { //如果src指向的字符串不够size_t赋值长度,则补0
*dest = 0;
dest++;
}
else { //把src中的字符放入到dest中
*dest = *src;
dest++; src++;
}
*dest ='\0';//手动补字符串结束标志
}
return ret;//返回dest字符串起始地址
}
int main()
{char str1[20] = "abcd";
char str2[] = "efg";
char* ret = my_strncat(str1, str2, strlen(str2));
puts(ret);
return 0;
}
strstr函数声明:*char * strstr ( const charstr1, const char * str2);
定位子字符串返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回空指针。
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[20] = "adasadsdf";
char s2[] = "asad";
char* ret = strstr(s1, s2); //返回s2在字符串s1中首次出现的位置
printf("%s", ret); //输出asadsdf
return 0;
}
模拟实现:
#include#include
//模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{const char* s1 = str1;
const char* s2 = str2;
const char* cp = s1;
while (*cp) //判断当前指针cp指向的位置的字符是不是结束标志,如果不是,继续进入循环
{s1 = cp;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
//字符串s1不结束,s2不结束,并且*s1跟*s2指向的字符相同,遍历往后走
{ s1++; s2++;
}
if (*s2 == '\0') //如果字符串s2遍历完依旧没有跳出循环,表示s2在字符串s1中出现
{ return cp;//返回当前位置
}
cp++;//当前指针向后遍历
}
return NULL;
}
int main()
{char s[] = "adafassb";
char s1[] = "sb";
printf("%s", my_strstr(s, s1));
return 0;
}
strtok函数声明:char * strtok ( char * str, const char * sep );
对此函数的一系列调用将 str 拆分为标记,这些标记是由分隔符中的任何字符分隔的连续字符序列。
在第一次调用时,该函数需要一个 C 字符串作为 str 的参数,其第一个字符用作扫描令牌的起始位置。在后续调用中,该函数需要一个空指针,并使用最后一个令牌末尾之后的位置作为扫描的新起始位置。
为了确定标记的开头和结尾,该函数首先从起始位置扫描分隔符中未包含的第一个字符(该字符将成为标记的开头)。然后从令牌的开头开始扫描分隔符中包含的第一个字符,该字符将成为令牌的末尾。如果找到终止空字符,扫描也会停止。
令牌的此结尾将自动替换为空字符,并且令牌的开头由函数返回。
一旦在对 strtok 的调用中找到 str 的终止空字符,则对此函数的所有后续调用(以空指针作为第一个参数)都将返回空指针。
找到最后一个令牌的点由要在下一次调用中使用的函数在内部保留(不需要特定的库实现来避免数据争用)。
实例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char arr[] = "Tzhenchuan@yeah.net";
char* p = "@.";
char* ret = NULL;
for (ret = strtok(arr, p);ret != NULL; ret = strtok(NULL, p))
{printf("%s\n", ret);
}
// 输出
// Tzhenchuan
// yeah
// net
return 0;
}
streror函数声明:char * strerror ( int errnum );
调用函数strerror时,如果程序有错误就会产生一个错误码存放在errno中,使用函数sererror就可以打印出程序所报错误的类型
案例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#include#include//fopen()函数如果打开文件成功,就会返回一个有效的指针
// 如果打开失败,就会返回一个空(NULL)指针
int main()
{//打开文件 打开的是当前目录下面的文件 打开方式是r
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{printf("%s\n",strerror(errno));
//输出No such file or directory
//错误信息是没有这个文件或者文件夹
return 1;
}
fclose(pf);
pf = NULL;
return 0;
}
memcpy函数定义:void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的
实例:
int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = {0 };
memcpy(arr2, arr1, 20);
for (int i = 0; i< 10; i++)
{printf("%d ", arr2[i]);
}//输出结果:1 2 3 4 5 0 0 0 0 0
return 0;
}
模拟实现:
#include#include
void* my_memcpy(void* dest, const char* src,size_t num)
{//设计函数的时候为了使得传入的数据兼容,采用void*指针接受可以兼容传入的指针
//将void*指针统一强转成(char*)指针进行操作,参数传入的num实际上表示要改变多少个字节的值
void* ret = dest;//存放要返回的地址
assert(dest && src);
while (num-- )//循环num次
{*(char*)dest = *(char*)src;//将void*类型强转成char*并对其所指向的内存进行赋值
dest = (char*)dest + 1;//由于dest跟src指针强转只是暂时的,不能进行自增操作
src = (char*)src + 1;//采用表达式的方式进行对dest和src指针的增操作
}
return ret;
}
int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9 };
int arr2[10] = {0 };
my_memcpy(arr2, arr1 + 2, 20);
return 0;
}
memmove函数声明:void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理
移动内存块将数字字节的值从源指向的位置复制到目标所指向的内存块。
实例:
#include#include
int main()
{int s[] = {1,2,3,4,5,6,7,8,9 };
memmove(s+2, s, 20);//数组内容变为 1,2,1,2,3,4,5,8,9
//从s数组第三个元素开始改为数组s第一个元素开始的5个元素 内存重叠
return 0;
}
模拟实现:
#include#include
void* my_memmove(char* dest, const char* src, size_t num)
{assert(dest && src);
//为了使内存重叠时也能进行操作,判断dest和src指针的位置进行两种不同的方式进行赋值操作
//memcpy原先设计的时候在内存重叠的时候操作会出错,memmove可以说是memcpy的改进版
if (dest< src)
{while (num--) { *(char*)dest = *(char*)src;//同上一个函数my_memcpy原理一样
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else {while (num--)
{ *((char*)dest + num) = *((char*)src + num);
}
}
}
int main()
{int s[] = {1,2,3,4,5,6,7,8,9 };
my_memmove(s+2, s, 20);
return 0;
}
memcmp函数声明:int memcmp ( const void * ptr1, const void * ptr2, size_t num );
将 ptr1 指向的内存块的前 num 字节数与 ptr2 指向的第一个字节数进行比较,如果它们都匹配,则返回零,如果不匹配,则返回一个不同于零的值,表示哪个值更大。 请注意,与 strcmp 不同,该函数在找到空字符后不会停止比较
实例:
#include#includeint main()
{char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
//比较两个字符串,返回一个值表示两个字符串的大小关系
if (n >0)
{printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
}
else if (n< 0)
{printf("'%s' is less than '%s'.\n", buffer1, buffer2);
}
else {printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
}
//输出'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'
return 0;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流