5、strcmp():字符串比较,C语言中字符串比较不能用=
12、strstr():字符串中查询字符串函数,若找到返回位置,否则返回Null
13、strchr():字符串中查询字符的函数,若找到返回位置,否则返回Null
14、strtok():分解字符串为一组字符串,使用方法如下
1、strcpy():复制字符串(不安全)
- 原型:char *strcpy(char *dest, const char *src);
- 功能:把src所指由'\0'结束的字符串复制到dest所指的数组中。
- 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
- 返回:指向dest的指针。
注意:当src串长度>dest串长度时,程序仍会将整个src串复制到dest区域,可是dest数组已发生溢出。因此会导致dest栈空间溢出以致产生崩溃异常。当达到最大尺寸时,它只是停止复制字符。
char* myStrcpy(char* pre, const char* next)
{
char out = pre;
if (pre == nullptr || next == nullptr) //空指针直接返回
{
return nullptr;
}
if (pre == next) // 两者相等也无需拷贝了
return pre;
while ((*pre++ = *next++) != '\0'); // 依次赋值给主字符数组
return out;
}
上面程序实现了strcpy的程序,实现很简单依次赋值给朱字符数组即可,当遇到next指向字符串结束字符’\0’后,完成赋值并且停止赋值。这样新赋值的’\0’就成了字符数组表示的字符串结尾符,哪怕主字符串pre比next长也会戛然而止。字符串判断不管字符数组存了啥,它只认到’\0’前的数是它的主体核心部分。strcpy没有检查长度会溢出,推荐使用strncpy。
2、strncpy():复制n个字符串(安全)
- 原型:char * strncpy(char*dest, char *src, size_t n);
- 功能:将字符串src中最多n个字符复制到字符数组dest中(它并不像strcpy一样遇到NULL才停止复制,而是等凑够n个字符才开始复制),
- 返回:指向dest的指针。
说明:如果n > dest串长度,dest栈空间溢出。否则:
1)src串长度<=dest串长度,(这里的串长度包含串尾NULL字符)
如果n=(0, src串长度),src的前n个字符复制到dest中。但是由于没有NULL字符,所以直接访问dest串会发生栈溢出的异常情况。
如果n = src串长度,与strcpy一致。
如果n = dest串长度,[0,src串长度]处存放src字串,(src串长度, dest串长度]处存放NULL。
2)src串长度>dest串长度
如果n =dest串长度,则dest串没有NULL字符,会导致输出会有乱码。
char *strncpy(char *strDest , const char *strSrc , int n)
{
assert((strDest != NULL) && (strSrc != NULL));
char *address = strDest;
while(n-- > 0)
*strDest++ = *strSrc++;
return address;
}
3、strcat():连接字符串(不安全)
- 函数原型:char* strcat(char* des, char* src),
- 函数功能:把src所指向的字符添加到dest结尾处(覆盖原dest结尾处的'\0'),并添加新的'\0'。
- 说明:des 和 src 所指内存区域不可以重叠且 des 必须有足够的空间来容纳 src 的字符串。
- 返回值:指向des的指针
strcat函数常见的错误就是数组越界,即两个字符串连接后,长度超过第一个字符串数组定义的长度,导致越界。
char* myStrcat(char* pre, const char* next)
{
if (pre == nullptr || next == nullptr) // 如果有一个为空指针,直接返回pre
return pre;
char* tmp_ptr = pre + strlen(pre); //strlen计算字符数,需要包含都文件string.h,当然也可以自己实现
while ( (*tmp_ptr++ = *next++) != '\0'); // 依次接着赋值
return pre;
}
由于strcat也容易造成缓冲区溢出,因此推荐使用strncat.
4、strncat():连接n个字符串(安全)
strncat把src所指向的字符的前n个字符添加到dest结尾处(覆盖原dest结尾处的'\0'),并添加新的'\0'。src和dest所指内存区域不可以重叠,并且dest必须有足够的空间来容纳src的前n个字符串,返回指向dest的指针。
char *strncat(char *dest,const char *str,int n)
{
assert((dest!=NULL)&&(str!=NULL));
char *cp=dest;
while(*cp!='\0') ++cp;
while(n&&(*cp++=*str++)!='\0')
{
--n;
}
return dest;
}
由于这四个函数都可能造成缓冲区溢出,在VS2015中已经禁用这几个函数。
5、strcmp():字符串比较,C语言中字符串比较不能用=
strcmp函数是C/C++中基本的函数,它对两个字符串进行比较,然后返回比较结果,函数形式为:int strcmp(const char* str1, const char* str2)。其中str1和str2可以是字符串常量或者字符串变量,返回值为整形。返回结果如下规定:
① str1小于str2,返回负值或者-1(VC返回-1);
② str1等于str2,返回0;
③ str1大于str2,返回正值或者1(VC返回1);
strcmp函数实际上是对字符的ASCII码进行比较,实现原理如下:首先比较两个串的第一个字符,若不相等,则停止比较并得出两个ASCII码大小比较的结果;如果相等就接着 比较第二个字符然后第三个字符等等。无论两个字符串是什么样,strcmp函数最多比较到其中一个字符串遇到结束符'/0'为止,就能得出结果。代码实现如下(参考):
int strcmp(const char* str1, const char* str2)
{
int ret = 0;
while(!(ret=*(unsigned char*)str1-*(unsigned char*)str2) && *str1){
str1++;
str2++
}
if (ret < 0){
return -1;
}
else if(ret > 0){
return 1;
}
return 0;
}
6、strlen():字符串长度
strlen()用于计算字符数组长度,到字符串结束符’\0’即停止。如:
char nzArr[] = "abcdef";
int nLen = strlen(nzArr); //结果为6,并不是100,和分配数组内存大小无关,不包含'/0'
int nLen = sizeof(nzArr); //结果为7,包括'/0'
7、strset():字符串重置
strset()用于设定字符数组全为某一字符,如果存在‘\0’结束符,遇结束符停止赋值。
char nzArr[100]="abcd";
strset(nzArr,'g'); //nzArr结果为“gggg”,如果未初始化,则100个空间都为'g'
9、memset():内存重置
memset()与strset()类似,赋值字符数组指定字符,但可以指定个数。
char nzArr[100]="abcd";
memset(nzArr,'g',sizeof(nzArr)); //nzArr中全为g,该函数是空间操作,不遇'\0'停止,输出g后会出现乱码
10、memcpy():内存复制(不安全)
memcpy()由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。
- 函数原型为:void *memcpy(void*dest, const void *src, size_t n);
- 函数返回一个指向dest的指针。
函数实现:
void* memcpy(void* dest, const void* src, size_t n)
{
char* d = (char*) dest;
const char* s = (const char*) src;
while(n-–)
*d++ = *s++;
return dest;
}
strcpy和memcpy主要有以下3方面的区别。
- 复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
- 复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
- 用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。
#include<stdio.h>
#include<string.h>
int main(){
char*s="Golden Global View";
chard[20];
clrscr();
memcpy(d,s,strlen(s));
d[strlen(s)]='\0'; //因为从d[0]开始复制,总长度为strlen(s),d[strlen(s)]置为结束符
printf("%s",d);
getchar();
return0;
}
输出结果:GoldenGlobal View
11、memmove():内存复制(安全)
memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。但当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也增加了一点点开销。memmove的处理措施:
- (1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
- (2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
- (3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
- 函数原型:void* memmove(void* dest, const void* src, size_t n)
- 返回值:函数返回一个指向dest的指针。
函数实现:
void* memmove(void* dest, const void* src, size_t n)
{
char* d = (char*) dest;
const char* s = (const char*) src;
if (s>d)
{
// start at beginning of s
while (n--)
*d++ = *s++;
}
else if (s<d)
{
// start at end of s
d = d+n-1;
s = s+n-1;
while (n--)
*d-- = *s--;
}
return dest;
}
12、strstr():字符串中查询字符串函数,若找到返回位置,否则返回Null
char *strchr(const char *s, int c)
{
if(s == NULL)
{
return NULL;
}
while(*s != '\0')
{
if(*s == (char)c )
{
return (char *)s;
}
s++;
}
return NULL;
}
13、strchr():字符串中查询字符的函数,若找到返回位置,否则返回Null
char *strstr(char*str, char *subStr)
{
while (*str != '\0') {
char *p = str;
char *q = subStr;
char *res = NULL;
if (*p == *q) {
res = p;
while (*q != '\0' && *p == *q){
p++;
q++;
}
if (*q =='\0')
return res;
}
str++;
}
}
char nzArr[10] = "ababcde";
char nzBuf[10] = "abc";
char* nzCount = (char*)malloc(sizeof(char)*10);
char* nzCount1 = (char*)malloc(sizeof(char)*10);//结果分配空间
memset(nzCount, 0, sizeof(nzCount)); //赋初值
memset(nzCount1, 0, sizeof(nzCount1)); //防止未匹配到指定字符或字符数组,而成为野指针
nzCount = strstr(nzArr, nzBuf); //返回为'abcde'
nzCount1 = strstr(nzArr, 'c'); //返回为'cc'
strstr()和strchr()都是查找第二个参数第一次出现在第一个字符数组的位置,前者是查找字符数组,而后者是字符。但是注意返回,返回的是参数出现的地址,需要赋给char*指针来存储,而不是一个索引。
14、strtok():分解字符串为一组字符串,使用方法如下:
#include <string.h>
#include <stdio.h>
int main ()
{
char str[80] = "This is - www.runoob.com - website";
const char s[2] = "-";
char *token;
token = strtok(str, s);
while( token != NULL )
{
printf( "%s\n", token );
token = strtok(NULL, s);
}
return(0);
}
参考:https://blog.csdn.net/FX677588/article/details/76702319
https://blog.csdn.net/lanzhihui_10086/article/details/39828901
https://blog.csdn.net/wgenek/article/details/7257435
https://blog.csdn.net/fx677588/article/details/53102634
https://www.cnblogs.com/kekec/archive/2011/07/22/2114107.html