《C和指针》读书笔记(第九章 字符串、字符和字节)(中)

简介: 《C和指针》读书笔记(第九章 字符串、字符和字节)(中)

4 长度受限的字符串函数

有的库函数在调用的时候,需要传入待处理的字符串的长度,因此称为长度受限的字符串函数。

这些函数提供了一种方便的机制,可以防止难以预料的长字符串从它们的目标数组溢出。

常见的有一下几个函数:

char    *strncpy(char  *dst,  char  const  *src,  size_t  len);
char    *strncat(char  *dst,  char  const  *src,  size_t  len);
int    strncmp(char  const  *s1,  char  const  *s2,  size_t  len);

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  char message1[] = "hello ";
  char message2[] = "hello Beijing ";
  char message3[] = "Shanghai";
  char message_all[] = "hello Beijing Shanghai";
  if(strncmp(strncpy(strncat(message2, message3, strlen(message3)), message1, strlen(message1)), message_all,strlen(message_all)) == 0)
    printf("二者相等\n");
  else
    printf("二者不相等\n");
  system("pause");
  return 0;
}

打印输出:

这个例子举得并不十分恰当。因为长度都是按最大进行传入的,但也可以说明问题。

5 字符串查找基础

标准库中存在很多函数,它们用各种不同的方法查找字符串。这些各种各样的工具给了C程序员很大的灵活性。

5.1 查找一个字符串

在一个字符串中查找特定字符有两个库函数可用。

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

前者用来查找某字符第一次出现的位置(返回指向该地址的指针),后者用来查找某字符最后一次出现的位置(返回指向该地址的指针)。

这两个函数可以这样用:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  char message1[] = "hello ";
  char message2[] = "hello Beijing ";
  char message3[] = "Shanghai";
  char message_all[] = "hello Beijing Shanghai";
  char *first_site, *last_site;
  first_site = strchr(message_all, 'h');
  last_site = strrchr(message_all, 'h');
  printf("字符串的长度是:%d\n",strlen(message_all));
  printf("h第一次出现的位置是:%d\n", first_site - message_all);
  printf("h最后一次出现的位置是:%d\n", last_site - message_all);
  system("pause");
  return 0;
}

打印输出:

需要注意的是,该函数返回的并不是目标元素位置的值,而是指针,所以需要与该字符串的第一个元素指针作差,才可以得出结果。

注意:在查找的时候是区分大小写的。

5.2 查找任何几个字符

strpbrk是一个更为常见的函数,用来查找某个字符串中任意字符第一次在目标字符串中出现的位置。它的原型如下:

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

可以这样用:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  char message_all[] = "hello Beijing Shanghai";
  char *first_site;
  first_site = strpbrk(message_all, "abcde");
  printf("字符串的长度是:%d\n",strlen(message_all));
  printf("abcde第一次出现匹配字符的位置是:%d\n", first_site - message_all);
  system("pause");
  return 0;
}

打印输出:

容易看出,第一个匹配到的字符是e,位置是1

5.3 查找一个子串

为了在字符串中查找一个子串,我们可以使用strstr函数,它的原型如下:

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

举个实际使用中的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  char message_all[] = "hello Beijing Shanghai";
  char *first_site;
  first_site = strstr(message_all, "Beijing");
  printf("字符串的长度是:%d\n",strlen(message_all));
  printf("Beijing第一次出现的位置是:%d\n", first_site - message_all);
  system("pause");
  return 0;
}

打印输出:

可以看到,在此次查找中,需要匹配到所有的字符,而不是某个或者局部。

6 高级字符串查找

接下来的一组函数简化了从一个字符串的起始位置中查找和抽取一个子串的过程。

6.1 查找一个字符串前缀

strspnstrcspn函数用于在字符串中的起始位置对字符串计数,它们的原型如下所示:

size_t  strspn(  char  const   *str,  char const  *group);
size_t  strcspn(  char  const   *str,  char const  *group);

需要注意的是,这两个函数返回的 并不是元素指针,而是实际匹配字符的数量。

具体的使用方法可以来看个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  int len1, len2;
  char buffer[] = "25,142,330,smith,J,239-4123";
  len1 = strspn(buffer, "0123456789");
  len2 = strcspn(buffer, ",");
  printf("0123456789的起始匹配数是:%d\n", len1);
  printf(",的起始不匹配数是:%d\n", len2);
  system("pause");
  return 0;
}

打印输出:

从上面例子中可以看出,strspn函数是从头开始找符合所找字符串的字符,直到找不到为止。在该例中,,已经不合适了,所以连续查找的情况下,合适的只有2个。

strcspn函数却恰好相反,找的是不符合的,开头的2和5显然都不符合,,是符合的,所以连续查找的情况下,合适的有2个。

6.2 查找标记

一个字符串常常包含好几个单独的部分,他们彼此被分隔开。每次为了处理这些部分,首先必须把它们从字符串中抽取出来。

strtok函数就可以实现这样的功能。它从字符串中隔离各个单独的称为标记的部分。并丢弃分隔符。它的原型如下:

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

注意:

  1. 当strtok函数执行任务时,它会修改它所处理的字符串。如果源字符串不能被修改,那就复制一份,将这份拷贝传递给strtok函数。
  2. 如果strtok函数的第1个参数不是NULL,函数将找到字符串的第1个标记。strtok同时将保存它在字符串中的位置。如果strtok函数的第1个参数是NULL,函数就在同一个字符串中从这个被保存的位置开始像前面一样查找下一个标记。

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  int add = 0;
  char buffer[] = "25,142,330,smith,J,239-4123";
  char *token = NULL;
  for (token = strtok(buffer, ","); token != NULL; token = strtok(NULL, ","))
  {
    printf("%s\n", token);
    add++;
  }
  printf("--------------------------\n");
  printf("add的值为:%d\n",add);
  system("pause");
  return 0;
}

打印输出:

从上面的例子中可以看出,以我们需要寻找的标记为分界,每循环一次,得到一个分割的子串,直到全部分割完毕。共分割6次。

7 错误信息

C语言的库函数在执行失败时,都会有一个错误码(0 1 2 3 4 5 6 7 8 9 …),操作系统是通过设置一个外部的整型变量errno进行错误代码报告的。也就是说,一个错误码,对应了一种错误类型,strerror函数把其中一个错误代码作为参数并返回一个指向用于描述错误的字符串的指针。这个函数的原型如下:

char  *strerror(int error_number);

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
  for(int i = 0; i < 10; i++)
    printf("%s\n",strerror(i));
  system("pause");
  return 0;
}

打印输出:

可以看到,不同的操作码,对应着不同的错误类型,而错误码0表示没有错误。其他均表示各种各样的错误。这部分内容了解即可。不需要掌握。也不需要知道每个操作码究竟代表哪种错误。

8 字符操作

标准库包含了两组函数,用于操作单独的字符,它们的原型位于头文件ctype.h。第1组函数用于对字符串分类,而第2组函数用于字符转换。

8.1 字符分类

每个分类函数接受一个包含字符值的整形参数。函数测试这个字符并返回一个整形值,表示真或假。下面的表格列出了每个函数以及返回真所需要的条件。

函数 返回真所需要的条件
iscntrl 控制字符
isspace 空白字符:空格,换页’\f’,换行’\n’,回车’\r’,制表符’t’或垂直制表符’\v’
isdigit 十进制数字
isxdigit 十六进制数字,包含大小写形式的a~f
islower 小写字母
isupper 大写字母
isalpha 字母(大小写皆可)
isalnum 字母或数字
ispunct 任何不属于数字或字母的图形字符(可打印符号)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符

所以这些函数是用来判定字符串元素的, 举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main()
{
  char temp[] = "To carry things with great virtue";
  for (int i = 0; i < strlen(temp); i++)
  {
    if (islower(temp[i]))
      printf("temp[%d] : %c是小写字母\n", i, temp[i]);
    else if (isupper(temp[i]))
      printf("temp[%d] : %c是大写字母\n", i, temp[i]);
    else if(isspace(temp[i]))
      printf("temp[%d] : %c是空格\n", i, temp[i]);
  }
  printf("\n");
  system("pause");
  return 0;
}

打印输出:

可以看到,此时已经将temp每个元素究竟是大写字母还是小写字母,或者是空格进行了判定。

相关文章
|
6月前
|
存储 编译器 C语言
函数指针&&数组指针&&数组传参的本质&&字符指针(进阶篇)
函数指针&&数组指针&&数组传参的本质&&字符指针(进阶篇)
123 0
|
6月前
|
存储 C++
使用字符指针变量和字符数组的比较
使用字符指针变量和字符数组的比较
53 0
C4.
|
6月前
|
存储 程序员 C语言
C语言中如何通过指针引用字符串
C语言中如何通过指针引用字符串
C4.
64 0
|
6月前
|
C语言
C语言----字符数组&&指针
C语言----字符数组&&指针
44 0
|
6月前
【每日一题Day301】LC2337移动片段得到字符串 | 双指针 计分
【每日一题Day301】LC2337移动片段得到字符串 | 双指针 计分
47 0
|
6月前
|
算法 C语言
通过指针引用字符串
通过指针引用字符串
59 1
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
6月前
|
存储 C语言
字符指针变量与字符数组的比较
字符指针变量与字符数组的比较
46 3
|
6月前
|
存储 C语言
字符指针作为函数参数
字符指针作为函数参数
59 2
|
6月前
DAY-2 | 哈希表、指针与区间划分:字符种数统计问题
```markdown ## 题干 [牛客网链接](https://www.nowcoder.com/practice/eb94f6a5b2ba49c6ac72d40b5ce95f50) ## 题解 1. **查表法(哈希表)**:利用数组标记出现过的 ASCII 值小于127的字符,首次出现计数,重复则忽略。 2. **指针与区间划分(回头法)**:遍历字符串,对每个字符检查其前所有字符是否重复,重复则不计数。 ## 方法总结 - 哈希表在去重问题中非常实用,可多做相关练习。 - 使用`continue`时注意避免死循环,确保循环变量会改变。 - 多回顾此类问题以巩固理解。 ```
41 2