字符串函数使用与剖析 & assert()宏 (自用详细整理)

assert()宏

断言:assert作为一种软件调试的方法,提供了一种在代码中进行正确性检查的机制。

assert()宏接受一个整形表达式参数。如果表达式的值为假,assert()宏就会调用_assert函数在标准错误流中打印一条错误信息,并调用abort()函数终止程序。

使用assert的好处:

  1. 能自动标识文件和出问题的行号
  2. 不需要更改代码就能开启或关闭assert机制(开不开启关系到程序大小的问题)。如果认为已经排除了程序的bug,就可以把 #define NDEBUG 写在assert.h前,并重新编译程序。这样编译器就会禁用工程文件中所有的assert语句。如果程序又出问题,可以移除这条#define指令,然后重新编译程序,这样就可以重新启用assert语句了。

assrt与if比较:

int* p = (int*)malloc(sizeof(int));
assert(p); //错误

assert在调试完毕之后会禁用掉,这样一来代码只剩下

int* p = (int*)malloc(sizeof(int));

assert与if做放错处理两点用法区别:

  1. assert用在debug版本中进行调试
  2. if(NULL != P)用在release版本中检查指针有效性。

求字符串长度

strlen

手动实现

int my_strlen(const char* str) //常量字符串
{
	int count = 0;
    assert(str != NULL); //断言
    
    while(*str) //*str != '\0'
    {
        count++;
        str++;
	}
    
    return count;
}

递归写法:不创建临时变量

MSDN

size_t strlen( const char *string );

库函数里的返回类型 size_t = unsigned int

总结:

1、字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’)

2、参数指向的字符串必须要以‘\0’结束

3、函数的返回值是size_t,无符号的(易错)

长度不受限制的字符串函数

遇到\0才停止:不安全

strcpy

MSDN

char *strcpy( char *strDestination, const char *strSource );

使用

int main()
{
    char arr1[] = "abcdefghij";
    char arr2[] = "bit";
    
    strcpy(arr1,arr2);
    return 0;
}

Output

bit

手动实现

char* my_strcpy(char* dest,const char*src)
{
    assert(dest != NULL);
    assert(src != NULL);
    
    char* ret = dest;
    //拷贝src指向的字符串到dest指向的空间,包含'\0'
    while(*dest++ = *src++)
    {
        ;
    }
    //返回目的空间的起始地址
    return ret;
}

1、源字符串必须以 '\0’结束

2、目标空间足够大,确保能够放源字符串

3、目标空间可变

strcat

Append a string. 追加一个字符串。

MSDN

char *strcat( char *strDestination, const char *strSource );

使用

int main()
{
    char arr1[30]="hello";
    char arr2[]="world";
    strcat(arr1,arr2);
    printf("%s\n",arr1);
    return 0;
}

Output

helloworld

模拟实现

char* my_strcat(char*dext,const char* src)
{
    char*ret = dest;
	assert(dest != NULL);
    assert(src);
    //当assert是NULL时,为假false
    
    //1.找到目的字符串的'\0'
    while(*dest != '\0')
        dest++:
    //2.追加
    while(*dest++ = *src++);
    return ret;
}

总结:

1、源字符串必须以 ‘\0’ 结束

2、目标空间必须足够大,能容纳下源字符串的内容

3、目标空间可修改

4、自己不可以追加自己

strcmp

compare strings

MSDN

int strcmp( const char *string1, const char *string2 );

对应字符进行比较

模拟实现

大于 返回1

相等 返回0

小于 返回-1

int my_strcmp(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;
}

大于 返回大于0

小于 返回小于0

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);
}

长度受限制的字符串函数

strncpy

Copy characters of one string to another.

char *strncpy( char *strDest, const char *strSource, size_t count );

count

Number of characters to be copied

你让我拷贝几个我就拷贝几个,不一定带 \0

总结:

1、拷贝count个字符从源字符串到目标空间。

2、如果源字符串的长度小于count,则拷贝完源字符串之后,在目标的后面追加0,直到count个。

strncat

Append characters of a string.指定长度追加字符串。

MSDN

char *strncat( char *strDest, const char *strSource, size_t count );

abcd\0xxxxxxx

总结:

1、追加结束后还是希望他是字符串,会主动放一个\0在后面。

2、str2的长度小于count,追加完了最后一个放 \0

strncmp

MSDN

int strncmp( const char *string1, const char *string2, size_t count );

strstr

Find a substring. 查找字符串

MSDN

char *strstr( const char *string, const char *strCharSet );

使用

int main()
{
   	char *p1 = "abcdefghj";
    char *p2 = "def";
    //strstr(p1, p2);
    //若存在,返回d的地址
    char* ret = strstr(p1, p2);
    if(ret == NULL)
    {
        printf("子串不存在!");
    }
    else
    {
        printf("%s\n",ret);
    }
    return 0;
}

Output

defghj

模拟实现

可进一步去研究KMP算法

#include <assert.h>

char* my_strstr(const char* p1, const char* p2)
{
	assert(p1 != NULL);
    assert(p2 != NULL);
    char *s1 = NULL;
    char *s2 = NULL;
    char *cur = (char*)p1;
    if(!*p2)
    {
        return (char*)p1; //p2是空字符串
    }
    while(*cur)
    {
        s1 = cur;
        s2 = (char* )p2; //强制类型转换
		while ((*s1==*s2) && *s2 && *s1)
        {
            s1++;
            s2++;       
        }
        if(!*s2)
        {
			return cur; //找到子串
        }
        if(*s1!)
        {
			return NULL; 
        }
        cur++;
    }
    return NULL; //找不到子串
}

案例:

1、 abbbcefh 和 bbc

2、abcdbcehj 和 bcd

strtok

Find the next token in a string.

MSDN

char *strtok( char *str, const char *sep );

sep参数是个字符串,定义了用作分隔符的字符集合。

sep去切割str

192.168.31.121   
192 168 31 121  - strtok    分隔符 .
    
zpw@bit.com  分隔符 @ .
  

把找到的字符用\0代替。

strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok将保存他在字符串中的位置。(函数内部有一个静态变量)

使用

#include <stdio.h>
#include <string.h>

int main()
{
	char arr[] = "192.168.31.121";
	char* p = ".";

	char buf[1024] = { 0 };
	strcpy(buf, arr);

	char* ret = NULL;

	for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}
	return 0;
}

先拷贝一份原串,防止对原先字符串进行改变。

strerror

错误报告函数:返回错误码,对应的错误信息(返回地址 char*)

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	//错误码 - 错误信息
	//0 - No error
	//1 - Operation not permitted
	//2 - No such file or directory

	//strerror将错误码翻译成错误信息

	//char* str = strerror(4);

	//errno是全局的错误码变量
	//C语言的库函数在执行过程中发生了错误,就会把对应的错误码,赋值到errno中
	char* str = strerror(errno);
	printf("%s\n", str);

	return 0;
}

errno是全局的错误码变量
C语言的库函数在执行过程中发生了错误,就会把对应的错误码,赋值到errno中

使用

打开文件

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (!pf)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		printf("open file success\n");
	}
	return 0;
}

内存函数

memcpy

内存拷贝

Copies characters between buffers.(缓冲区)

void *memcpy( void *dest, const void *src, size_t count );

count单位是字节

sizeof(数组名):数组的地址 ----->>> 数组的大小

&数组名:数组的地址

模拟实现

#include <assert.h>

void my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
    assert(dest != NULL);
    assert(dest != NULL);
    
    while(num--)
    {
		*(char*)dest = *(char*)src;
        ++(char*)dest;  //先强制类型转换再 ++
        ++(char*)src;
    }
    return ret;
}

memmove

void *memmove( void *dest, const void *src, size_t count );

C语言标准说,memcpy 只要处理 不重叠的内存拷贝就可以,当下发现:VS2013环境下的memcpy可以处理重叠拷贝。

memmove 处理重叠内存的拷贝

memcmp

int memcmp( const void *buf1, const void *buf2, size_t count );
< 0   buf1 less than buf2 
0     buf1 identical to buf2 
> 0   buf1 greater than buf2 

memset

内存设置

void *memset( void *dest, int c, size_t count );

使用

#include <stdio.h>
#include <string.h>

int main()
{
	char arr[10] = "";

	memset(arr, 'c', 10);

	return 0;
}

易错点

#include <stdio.h>
#include <string.h>

int main()
{
	int arr[10] = { 0 };
	
	//40个字节
	// hex
	// 01 01 01 01 | 01 01 01 01 | 01 01 00 00 00 ...
	memset(arr, 1, 10);

	return 0;
}

count的单位是字节,修改的单位是字节。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JoyCheung-

赏颗糖吃吧~~~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值