C语言--常见的字符串函数及其模拟实现

前言

C库提供了多个处理字符串的函数,ANSI C把这些函数的原型放在string.h头文件中。其中最常用的函数有 strlen()、strcat()、strncat()、strcmp()、strncmp()、strcpy()和 strncpy()。另外,还有sprintf()函数,其原型在stdio.h头文件中。

一、strlen()函数

strlen()函数用于统计字符串的长度。

int strlen(char const*string);

获取字符串的长度,返回的是字符的个数,但是不会包括’\0’(结束符)。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "This is strlen function!";
	printf("%d\n",strlen(arr));
	return 0;
}

输出示例:

24

模拟strlen函数实现:

#include<stdio.h>
#include<assert.h>
int myStrlen(const char* arr)
{
	int n = 0;
	assert(arr);
	while (*arr != '\0')
	{
		n++;
		arr++;
	}
	return n;
}

二、strcat()和strncat()函数

strcat()和strncat()函数都是将str2指向的字符串连接到str1指向的字符后面,同时会删除str1后面的’\0’,返回的是str1指向字符串的首地址。
2.1 strcat()函数
strcat()(用于拼接字符串)函数接受两个字符串作为参数。该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后形成的新字符串作为第1个字符串,第2个字符串不变。

char* strcat(char *string1,char *string2);

strcat()函数的类型是char *(即,指向char的指针)。strcat()函数返回第1个参数,即拼接第2个字符串后的第1个字符串的地址。源字符必须以’\0’结束,且目标空间必须足够大,以确保能存放源字符串 。

char arr1[10]="abc";
	char arr2[] = "def";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	printf("%s\n", arr2);

输出示例:

abcdef
def

模拟strcat函数实现:

void myStrcat(char* arr1,char* arr2)
{
	assert(arr1 != NULL);
	assert(arr2 != NULL);
	while (*arr1 != '\0')
	{
		arr1++;
	}
	while (*arr2 != '\0')
	{
		*arr1 = *arr2;
		arr1++;
		arr2++;
	}
}

2.2 strncat()函数
strcat()函数无法检查第1个数组是否能容纳第2个字符串。如果分配给第1个数组的空间不够大,多出来的字符溢出到相邻存储单元时就会出问题。strncat()函数则能解决这个问题,strncat函数可以将字符串str2(源头)连接在字符串str1(目标)后面,count决定你要连接str2中的几个字符,当然要注意str1(目标)的空间要足够大,应该足以接受连接的字符。

char *strncat( char *str1, const char *str2, size_t count );

该函数的第3 个参数指定了最大添加字符数。

char arr1[10]="abc";
	char arr2[] = "def";
	strncat(arr1, arr2, 3);
	printf("%s\n", arr1);

三、strcmp()和strncmp()函数

两个函数都是按照ASCII码来进行比较,并由函数返回值进行判断:
1、返回0,字符串1等于字符串2;
2、大于0,字符串1大于字符串2;
3、小于0,字符串1小于字符串2。

3.1 strcmp()函数

int strcmp(const char * _Str1,const chart* _Str2);

该函数通过比较运算符来比较字符串,就像比较数字一样。如果两个字符串参数相同,该函数就返回0;如果字符串1大于字符串2,就返回大于零值;如果字符串1小于字符串2,就返回小于零值。要注意的是,这个区分大小写,“ABC”和“abc”的ASCII码不同。

/* 程序3.1 -- 该程序可以正常运行 */
#include<stdio.h>
#include<string.h>
#define STR "ABC"
#define STRLEN 40
int main()
{
	char word[STRLEN];
	gets_s(word, STRLEN);
	puts(word);
	while (strcmp(word, STR) != 0)
	{
		puts("No, that's wrong. Try again.");
		fgets(word, STRLEN, stdin);
	}
	puts("That's right!");
	return 0;
}

strcmp()函数比较的是字符串,不是整个数组,这是非常好的功能。虽然数组word占用了40字节,而储存在其中的"ABC"只占用了4字节(还有一个用来放空字符’\0’),strcmp()函数只会比较word中第1个空字符前面的部分。所以,可以用strcmp()比较储存在不同大小数组中的字符串。
模拟strcmp函数实现:

int myStrcmp(const char* str1,const char* str2)
{
	while (*str1!='\0'&&*str2!='\0')
	{
		int x = *str1 - *str2;
		if (x == 0)
		{
			str1++;
			str2++;
		}
		else
		{
			return x;
		}
	}
	if (*str1 == '\0' && *str2 == '\0')
	{
		return 0;
	}
	else
	{
		if (*str1 == '\0' && *str2 != '\0')
			return -1;
		else
			return 1;
	}
}

3.2 strcnmp()函数
strcmp()函数比较字符串中的字符,直到发现不同的字符为止,这一过程可能会持续到字符串的末尾。而strncmp()函数在比较两个字符串时,可以比较到字符不同的地方,也可以只比较第3个参数指定的字符数。

int strncmp(const char*str1,const char *str2,int size);

例如,要查找以"astro"开头的字符串,可以限定函数只查找这5 个字符。程序3.2 演示了该函数的用法。

/* 程序3.2-- 使用 strncmp() */
#include <stdio.h>
#include <string.h>
#define LISTSIZE 6
int main()
{
const char * list[LISTSIZE] ={
"astronomy", "astounding",
"astrophysics", "ostracize",
"asterism", "astrophobia"
};
int count = 0;
int i;
for (i = 0; i < LISTSIZE; i++)
if (strncmp(list[i], "astro", 5) == 0)
{
printf("Found: %s\n", list[i]);
count++;
}
printf("The list contained %d words beginning"" with astro.\n", count);
return 0;
}

输出示例:

Found: astronomy
Found: astrophysics
Found: astrophobia
The list contained 3 words beginning with astro.

四、strcpy()和strncpy()函数

char *strcpy(char*des,char*src);
char *strncpy(char *des,char *src,int size);

strcpy()和strncpy()函数都是将src指向的字符串拷贝到des指向的字符串数组中去,其中strncpy()函数中的size参数也可以拷贝制定长度的字符串,建议des为字符数组。
注意:目标尽量使用字符数组,因为如果是字符指针的话,分配的内存在常量池中,是不允许进行改变的,容易造成段错误。
4.1 strcpy()函数
将src指向的字符串拷贝到des指向的字符串数组中去,**结束符也一同进行拷贝。**操作成功,返回这个字符(des的地址)
注:目标空间必须足够大,以确保能存放源字符串。

char *strcpy(char*des,char*src);

strcpy()接受两个字符串指针作为参数,可以把src声明为指针、数组名或字符串常量;而des指针应指向一个数据对象(如数组),且该对象有足够的空间储存源字符串的副本,**如果des未被初始化,src指向的字符串可能被拷贝到任意的地方!**记住,声明数组将分配储存数据的空间,而声明指针只分配储存一个地址的空间。

#include<stdio.h>
#include<string.h>
#define STRLEN 40
#pragma warning(disable:4996)
int main()
{
	char des[STRLEN];
	char src[STRLEN]="This is strcpy function!";
	char* temp;

	temp=strcpy(des, src);

	puts(des);
	puts(temp);
	return 0;
}

输出示例:

This is strcpy function!
This is strcpy function!

模拟strcpy函数实现:

#include<stdio.h>
#include<assert.h>
char* myStrcpy(char* str1,const char* str2)
{
	assert(str1 != NULL);
	assert(str2!=NULL);
	while (*str2 != '\0')
	{
		*str1 = *str2;
		str1++;
		str2++;
	}
	*str1 = *str2;//将源字符串中的'\0'拷贝到目标空间
	return str1;
}

4.2 strncpy()函数
strcpy()函数不能检查目标空间是否能容纳源字符串的副本。拷贝字符串使用 strncpy()更安全,该函数的第 3 个参数指明可拷贝的最大字符数。

char *strncpy(char *des,char *src,int size);

将src指向的字符串拷贝到des指向的字符串数组中去,拷贝的字符串长度取决于size参数,结束符’\0’可能会不进行拷贝(把src中的size个字符或空字符之前的字符(先满足哪个条件就拷贝到何处)拷贝至des中。)。

#include<stdio.h>
#include<string.h>
#define STRLEN 40
#pragma warning(disable:4996)
int main()
{
	char des1[STRLEN];
	char des2[STRLEN];
	char src[STRLEN]="This is strncpy function!";
	char* temp1;
	char* temp2;

	temp1=strncpy(des1, src, STRLEN);
	temp2 = strncpy(des2, src, 5);//结束符'\0'未进行拷贝
	puts(des1);
	puts(temp1);
	puts(des2);
	puts(temp2);
	return 0;
}

输出示例:

This is strncpy function!
This is strncpy function!
This 烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘐his is strncpy function!
This 烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘐his is strncpy function!

如果拷贝到目标空间的字符串长度小于源字符串长度或目标空间装不下拷贝的副本,则把目标空间最后一个元素设置为空字符。

五、sprintf()函数

sprintf()函数声明在stdio.h中,而不是在string.h中。该函数可以把多个元素组合成一个字符串,sprintf()的第1个参数是目标字符串的地址。其余参数和printf()相同,即格式字符串和待写入项的列表。返回buffer的长度。

int sprintf( char *buffer, const char *format [, argument,…] );
#include<stdio.h>
#include<string.h>
#include<assert.h>
#define STRLEN 40
#pragma warning(disable:4996)
int main()
{
	char des[2*STRLEN];
	char src[STRLEN]="This is sprintf function";
	int i=sprintf(des,"%s %s %d",src,src,521);
	printf("%d\n", i);
	puts(des);

	return 0;
}
上一篇:青少年蓝桥杯_2020_每日一题_3.19_约分


下一篇:大数运算(加法)