字符串和内存操作函数

字符串函数和内存函数

  • 一字符串函数
    • 1.求字符串长度strlen
    • 2. 长度不受限制的字符串函数
      • strcpy
      • strcat
      • strcmp
    • 3.长度受限制的字符串函数
      • strncpy
      • strncat
      • strncmp
    • 4.字符串查找
      • strstr
    • 5.错误信息和字符操作。
      • strtok
      • strerror
      • 字符分类函数
  • 二.内存操作函数
    • memcpy
    • memmove
    • memcmp

一字符串函数

1.求字符串长度strlen

看函数原型size_t strlen ( const char * str );
sizeof_t 无符号整形,返回的字符串长度的数值类型
cnost char*str 传入进来的字符串首元素地址
注意
1.参数指向的字符必须要以\0 结束
2.没有找到\0就1一直向后寻找。

模拟实现strlen

//1.计数器方法
size_t my_strlen(const char* arr)
{
	assert(arr);
	size_t count = 0;
	while (*arr++)
	{
		count++;
	}
	return count;
}


//2.指针-指针
size_t my_strlen(const char* arr)
{
	char* begin = arr;
	while (*arr++)
	{
		;
	}
	return (size_t)((arr - begin)-1);
}


//3.递归的方法
size_t my_strlen(const char* arr)
{
	if (*arr == '\0')
	{
        return 0;
	}
	else
	{
		return 1+my_strlen(arr+1);
	}	
}
int main()
{
	char arr[] = "abcdef";
	printf("%d", my_strlen(arr));
	return 0;
}

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

strcpy

函数原型:char * strcpy(char * dest , const char * sour)

功能:将原字符串拷贝到目标字符串中

1.源字符串必须以 ‘\0’ 结束。
2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。

模拟实现

//模拟实现strcpy
char* my_strcpy(char* dest ,const char* source)
{
	assert(dest != NULL);
	assert(source != NULL);


	char* begin = dest;
	//因为*source到了\0之后就是最后一次赋值就结束循环
	//\0在数值上是0
	while (*dest++ = *source++)
	{
		;
	}
	return begin;
}
int main()
{
	char arr[20] = "xxxxxxxx";
	char arr2[] = "hello word";
	char* p=my_strcpy(arr,arr2);
	//char* p = strcpy(arr, arr2);
	printf("%s", p);
	return 0;
}

strcat

函数原型:char * strcat(char * dest , const char*sour)

功能:将原字符串追加到目标字符串后面并且目标字符串原来的的\0被覆盖

1.源字符串必须以 ‘\0’ 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
3.目标空间原来的\0或被覆盖。

模拟实现

//模拟实现strcat
char* my_strcat(char* dest, const char* source)
{
	assert(dest!=NULL);
	if (source == NULL)
	{
		return dest;
	}


	char* begin = dest;
	while (*dest)
	{
		dest++;
	}


	while (*dest++ = *source++)
	{
		;
	}
	return begin;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "word ";


	printf("%s\n", strcat(arr1, arr2));
	printf("%s", my_strcat(arr1, arr2));
	return 0;
}

字符串自己给自己追加,如何?
不可以的为什么呢?
abc\0
1.找到\0位置之后把a放到\0上面,我们这个字符串的\0就消失了。字符串追加就结束不了了;

strcmp

函数原型: int strcmp(char* str1 , char* str2)

函数功能:实现两个字符串比较一对一从头开始,直到一方或者双方到\0比较完成后就结束比较.

1.str1对应位置的字符大于str2就返回数值1
2.str1对应位置的字符小于str2就返回数值-1
3.str1对应位置的字符等于str2就返回数值0

模拟实现

//模拟实现strcmp


int my_strcmp(char* arr1, char* arr2)
{
	while (*arr1!='\0' || *arr2!='\0')
	{
		if (*arr1++ == *arr2++)
		{
			continue;
		}
		else if (*arr1 > *arr2)
		{
			return 1;
		}
		else if (*arr1 < *arr2)
		{
			return -1;
		}
	}
}


int main()
{
	char arr[] = "abcd";
	char arr2[] = "abcde";


	//printf("%d \n", strcmp(arr, arr2));
	printf("%d \n", my_strcmp(arr, arr2));
	return 0;
}

3.长度受限制的字符串函数

strncpy

函数原型:char * strcpy(char * dest , const char * sour ,zize_t num) 1.拷贝num个字符从源字符串到目标空间。2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
#include
#include

char* my_strncpy(char* dest, const char* source,size_t num)
{
	assert(dest != NULL);
	assert(source != NULL);
	char* begin = dest;
	//因为*source到了\0之后就是最后一次赋值就结束循环
	//\0在数值上是0
	while (num--)
	{
		if(*source != '\0')
		*dest++ = *source++;
		if (*source == '\0')
		{
			*dest++ = '\0';
		}
	}
	return begin;
}
int main()
{
	char arr[20] = "xxxxxxxxxxxxxx";
	char arr2[] = "hello word";
	char* p = my_strncpy(arr, arr2 ,3);
	//char* p = strcpy(arr, arr2);
	printf("%s", p);
	return 0;
}

strncat

函数原型:char * strncat(char * dest , const char * sour , zize_t num)

模拟实现

char* my_strncat(char* dest, const char* source, size_t num)
{
	assert(dest != NULL);
	if (source == NULL)
	{
		return dest;
	}

	char* begin = dest;

		
		while (*dest)
		{
			dest++;
		}


		while (num--)
		{
			if (*source != '\0')
			*dest++ = *source++;

			if (*source == '\0')
			{
			  *dest++ = '\0';
			}
		}
	
	return begin;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "word ";
	printf("%s", my_strncat(arr1, arr2,9));
	return 0;
}

strncmp

函数原型:char * strncmp(char * dest , const char * sour , zize_t num)

模拟实现

int my_strncmp(char* arr1, char* arr2,int num)
{
	int count = 0;
	while ((*arr1 != '\0'&& count < num) || (*arr2 != '\0' && count<num))
	{
		if (*arr1 == *arr2)
		{
			count++;
			*arr1++;
			*arr2++;
			continue;
		}
		else if (*arr1 > *arr2)
		{
			return 1;
		}
		else if (*arr1 < *arr2)
		{
			return -1;
		}
		
	}
}


int main()
{
	char arr[] = "abcd";
	char arr2[] = "adcde";


	//printf("%d \n", strcmp(arr, arr2));
	printf("%d\n",my_strncmp(arr, arr2,3));
	return 0;
}

总结:我们使用长度受控制的字符串函数去拷贝,追加,比较.我们可以通过手动输入操作原来字符串的操作长度,要比我们长度不受限制的好用并且安全,因为长度不受限制的字符串操作函数中,通过找的原函数的\0去停止字符串的拷贝,追加,比较.这样的方式有可能产生自己给自己操作的过程中由于\0位置内容改变而产生问题,也有可能有一些其他的情况导致\0原本的位置发生变化.

4.字符串查找

strstr

函数原型:char* strstr(const char* str1 , const char* str2)

功能:在str1中寻找str2第一次出现的位置并且返回并且返回str2的首元素第一次在str1中出现的位置
1.函数传入的参数都是不可以修改的.
2.这个函数在模拟实现的时候需要在函数中定义3个指针变量
cp:原来记录当前的str1的位置每次只移动一位直到\0结束
pstr1:每次循环开始先拿到cp的数值确定自己的开始位置,
pstr2:初始化我们子串的开始,每次循环结束更新位置还是字串的首元素地址.
没有找到子串的结束情况
1.cp移动到\0
2.pstr1在和pstr2的比较过程中先到了\0
模拟实现

#include
char* my_strstr(const char* str1, const char* str2)
{
	char* pstr1=str1;
	char* pstr2=str2;
	char* cp=str1;

	while (*cp)
	{
		pstr1 = cp;
		while (*pstr2 == *pstr1)
		{
				pstr1++;
				pstr2++;
		}
		//==注意只有子串到了\0才可以返回当前的cp的值==
		if (*pstr2 == '\0')
		{
			return cp;
		}
		cp++;
		pstr2 = str2;
	}
}

int main()
{
	char str1[] = "abddcfg";
	char str2[] = "dc";
	printf("%s", my_strstr(str1, str2));
	return 0;
}

5.错误信息和字符操作。

strtok

函数原型: char * strtok(char * str ,cnost char* sep); 1.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。) ==strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置== strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。 如果字符串中不存在更多的标记,则返回 NULL 指针。 2.sep中是用来存放在str中可能出现的分隔符.

1.创建一个临时变量去存放我们需要分隔的字符串.(strtok函数会改变被操作的字符串,将分隔符位置变为\0)
2.关于函数第一次传参:传临时变量的首元素的地址.进入函数之后就会在临时变量中向后寻找我们的分隔字符.
3.找到分隔字符把这个字符给变成\0.
4.如果进来的第一个就为sep我们就把他改为\0,返回这个\0的地址,并且保存下一个位置的地址在我们的静态变量中.
5.第二次寻找的过程中静态变量会赋值到一个移动变量,移动变量找到sep,改成\0,
返回当前的静态变量,改变静态变量的数值为找到的字符的下一个位置,有利于下一次的使用.
6.在我们的函数中应该使用了应该静态的变量去存放我们第一次找的的分隔符的下一个位置的地址.(对我们的第二次使用函数提供了方便)
7.第二次使用只需要strtok(NULL,sep);就可以实现第一次寻找的功能,

字符串和内存操作函数_第1张图片

strerror

函数原型:char * strerror(int errnum)

函数头文件:#include
功能:返回错误码对应的错误信息.

1.库函数在执行的时候发生了问题,我们会将一个错误的码放到error这个c语言提供的全局变量中.
2.在这个函数中提供了一个功能可以通过提供的错误码的数值返回在c语言中已经定义好的错误信息,获得字符串字符串信息就是错误码对应的错误信息.

字符串和内存操作函数_第2张图片

字符分类函数

函数 如果他的参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母az或AZ
isalnum 字母或者数字,az,AZ,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符

原理:根据对应数据的ASCII码的数值进行的判断.

二.内存操作函数

memcpy

函数原型:void * memcpy(void * dest ,const void *sour,size_t num) 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。 这个函数在遇到 '\0' 的时候并不会停下来。 如果source和destination有任何的重叠,复制的结果都是未定义的。

对于不同类型的使用:
字符串和内存操作函数_第3张图片
字符串和内存操作函数_第4张图片
字符串和内存操作函数_第5张图片

模拟实现:

void* my_memcpy(void* dest, const void* sour, size_t num)
{
	//因为num的单位是字节。
	char* top = (char*)dest;

	while (num--)
	{
		*(((char*)dest)++) = *(((char*)sour)++);

	}
	return top;
}
int main()
{
	int arr1[10] = {7,8,3,};
	int arr2[] = {1,2,3,4,5,6};
	int sz = sizeof(arr1) / sizeof(arr2[1]);
    int* p = my_memcpy(arr1, arr2, 8);
	for (int i = 0; i < sz; i++)
	{
		
		printf("%d ",*(p+i) );
	}
	return 0;
}

memmove

函数功能:函数主要通过传入的地址位置去进行移动字节拷贝,自己给自己拷贝从不同的位置开始,要考虑覆盖的问题我们应该怎么去实现拷贝的模拟过程不被影响!

函数原型:void * memcpy(void * dest ,const void *sour,size_t num)

字符串和内存操作函数_第6张图片

模拟实现

字符串和内存操作函数_第7张图片

void* my_memmove(void* dest, const void* sour, size_t num)
{
	//因为num的单位是字节。
	char* top = (char*)dest;

	if (dest < sour)
	{
		while (num--)
			{
				*(((char*)dest)++) = *(((char*)sour)++);
			}
	}
	else if (dest > sour)
	{
		(char*)dest += num;
		(char*)sour += num;
		while (num--)
		{
			*((--(char*)dest)) = *((--(char*)sour));
		}
	}

	
	return top;
}
int main()
{
	int arr1[10] = {7,8,3,4,5,9,6};
    int* p = my_memmove(arr1+3, arr1+1, 12);
	for (int i = 0; i < 7; i++)
	{
		printf("%d ",*(p+i) );
	}
	return 0;
}

memcmp

函数原型:int memcmp ( const void * ptr1, const void * ptr2, size_t num );

功能:从传入的两个位置开始依次向后去比较,num个字节,
*ptr1>*ptr2 返回1
*ptr1<*ptr2 返回-1
*ptr1==*ptr2 返回0

字符串和内存操作函数_第8张图片

模拟实现

字符串和内存操作函数_第9张图片

int my_memcmp(const void* s1, const void* s2, size_t num)
{
	while (num--)
	{
		if ((*((char*)s1)) == (*((char*)s2)))
		{
			((char*)s1)++;
			((char*)s2)++;
		}
		else if ((*((char*)s1)) > (*((char*)s2)))
		{
			return 1;
		}
		else if ((*((char*)s1)) < (*((char*)s2)))
		{
			return -1;
		}
	}

	return 0;
	
}
int main()
{
	int arr1[10] = { 7,8,3,4,5,9,6 };
	int arr2[] = { 7,8,2,4,5,9,6 };

	printf("%d\n", my_memcmp(arr1,arr2,8));
	printf("%d\n", my_memcmp(arr1, arr2, 12));
	printf("%d\n", my_memcmp(arr1, arr2, 16));
	return 0;
}

你可能感兴趣的:(程序人生,学习方法,c语言)