c和指针 -- 字符串、字符、字节

时间:2023-01-11 17:30:59

字符串基础

字符串就是一串零个或多个字符, 并且以一个位模式为全0的NUL字节结尾; 但是NUL并不是字符串的一部分, 所以字符串长度不包括NUL。

字符串长度

函数原型:

size_t strlen(char const *string)
{
int length;
for (length = 0; * length ++ = '\0'; )
length += 1;
return length;
}

size_t类型

这个函数中出现了size_t类型, 这个类型是在stddef.h中定义的, 它是一个无符号的整型。但是在表达式中可能导致不可预料的结果, 比如:

if (strlen (x) >= strlen (y))   // 1
if (strlen (s) - strlen (y) >= 0) // 2

这两个判断语句看上去功能是一致的, 但是它们其实是不同的。 第一个语句功能和你想的一样, 但是第二个语句就不是了, 因为size_t是无符号类型, 所以两个size_t类型相减的结果也是无符号数; 而无符号数不可能是负的; 如果你想消除这种影响, 可以将size_t类型强制转换为 int 类型。

不受限制的字符串函数

最常用的字符串函数都是“不受限制的”, 就是说它们只是通过寻找字符串参数结尾的NUL字节来判断它的长度。 这些函数一般都指定一块内存用于存放结果字符串。 在使用这些函数时, 程序员必须保证结果字符串不会溢出这块内存。

赋值字符串

strcpy函数

char *strcpy(char *dst,const char *src)  
{
assert(dst != NULL);
assert(src != NULL);
char *ret = dst;
memcpy(dst,src,strlen(src)+1);
return ret;
}

关于memcpy函数可以参考一下:memcpy函数详解

这个函数要注意的一些地方,

  1. 由于dst参数会被修改, 所以dst参数必须是一个字符数组或者动态分配内存空间的数组指针。
  2. 必须保证目标字符数组的空间足以容纳需要复制的字符串。 如果字符串比数组长, 多余的字符仍被复制, 它们将覆盖存储于dst数组后面的内容。
  3. 如果dst和src的在内存空间出现重叠, 结果是未定义的。

连接字符串

将一个字符串连接到一个字符串的后面, strcat函数

char * my_strcat(char * dest,const char *src)  
{
char *p=dest;
while(*p) p++; //让指针P指向dest的最后面
while(*src)
{
*p=*src;
p++;
src++;
}
*p='\0'; //新字符串的终止符
return dest;
}

这个函数要注意的一些地方。

  1. dst参数原先已经包含了一个字符串(可以为空)。它找到这个字符串的末尾, 并把sre字符串的一份拷贝加到这个位置。
  2. 如果dst和src在内存中的位置出现重叠, 结果是未定义的。
  3. 必须保证目标字符数组剩余的空间足以保存整个源字符串。(记住要加上原来的字符串

函数的返回值

strpy和strcat都返回它们第1个参数的一份拷贝, 就是指向目标字符串数组的指针。, 由于它们都返回这种类型的值, 所以可以嵌套使用这些函数:

strcat(strcat(dst, a), b);

strcpy首先执行, 将字符串a复制到dst并返回dst, 将这个返回值成为strcat函数的第一个参数, 再将字符串b连接到第一个参数后面。

字符串的比较

从第一个字符开始逐个比较, 知道发现不匹配的为止。 比较是以在字符集中的序数比较的, 对于第一个不匹配的字符, 该字符在字符集中的序数“小”, 则该字符串“较小”, 如果一个字符串包含另外一个字符串, 那么称被包含的那个字符串“较小”。 其实就是“词典比较”。

int strcmp (const char *str1, const char *str2)
{
int ret=0;
while (!(ret = *(unsignedchar*)str1 - *(unsignedchar*)str2) && *str1)
{
str1++;
str2++;
}
if (ret < 0)
{
return -1;
}
else if (ret > 0)
{
return 1;
}
return 0
}

如果 str1 < str2, 返回一个小于零的值, 如果 str1 > str2, 函数返回一个大于零的值。 如果两个字符串相等, 函数返回零。 并不是返回什么 -1, 1, 0。

长度受限的字符串函数

标准库中还包含了一些函数, 它们以一种不同的方式处理字符串。 这些函数接受一个显示的长度参数, 用于限定进行复制或比较的字符数。

下面是一些函数的受限形式, 它们的原型分别为:

char *strncpy (char *dst, char const *src, size_t len);
char *strncat (char *dst, char const *src, size_t len);
char strncmp (char const *s1, char const *s2, size_t len);
  1. 和strcpy一样, strncpy把源字符串的字符复制到目标数组中。 然而, 它总是正好向dst写入长度为len个字符。 如果strlen(src)的值小于len, dst数组就用额外的NUL字节填充到len长度。 如果len的值大于或等于len, 那么只有len个字符被复制到dst中。 注意:它的结果不会以NUL字节结尾
  2. strncat函数和strncpy不同之处在于。 它从src中最多复制len个字符到目标数组后面。 但是, strncat总是在结果字符串后面添加一个NUL字节, 而且它不会像strncpy那样对目标数组进行NUL字节填充。注意目标数组中原先的字符串并没有算在strncat的长度中。 strnct最多像目标数组复制len个字符。(再加一个NUL结尾)
  3. strncmp也是用于比较两个字符串, 但它最多比较len个字节。如果两个字符串在第len个字符之前存在不相等的字符, 这个函数就停止比较, 返回结果。 如果两个字符串的前len个字符相等, 函数返回零。

字符串查找

字符串的一些查找函数

查找一个字符串

strchr和strrchr函数。 它们的函数原型如下:

char * strchr (char const *str, int ch);
char * strrchr (char const *str, int ch);

函数用法说明:strchr函数在str中查找ch第一次出现的位置, 然后返回一个指向该位置的指针。 如果不存在返回NULL指针。 strrchr与strchr基本一致; 只不过查找的是该字符在字符串中最后出现的一个位置。

char string [20]  = "Hello there, honey";
char *ans;
ans = strchr(string, 'h');

ans会返回一个指向’h’的指针, 注意:这里是区分大小写的。

查找任何几个字符

strpbrk:查找任何一组字符第一次在字符串中的位置。 它的函数原型如下:

char * strpbrk(char const *str, char const *group);

这个函数返回一个指向str中第一个匹配group中任何一个位置的字符位置。 如果未匹配,返回NULL。

char string[20] = "hello there, honey";
char ans;
ans = strpbrk(string, "eafsd");

ans所指的位置是’e’的位置。

查找一个子串。

strstr:查找一个子串。 函数原型:

char * strstr(char const * s1 , char const * s2);

这个函数返回一个指向s2在s1中起始位置的指针。如果s2没有完整出现在s1的任何地方, 返回NULL指针。
注意:标准库中并不包含strrstr或strrpbrk函数(即返回指向最右边的指针)

字符操作

它们的原型位于ctype.h这个头文件中

字符分类

c和指针 -- 字符串、字符、字节

字符转换

int tolower(int ch);
int toupper(int ch);

tolower返回ch的小写形式, toupper返回ch的大写形式。(如果它们的参数形式与返回值形式一致, 函数将不修改参数直接返回)


参考自:c和指针