C语言标准库中字符串处理

214 阅读13分钟

C语言标准库中字符串处理

1、字符串输入/输出

1.1 字符串输出

printf()可以按照自己规定的格式输出字符串信息,一般称为格式化输出;而putchar()、puts()、fputc()、fputs() 这些函数只能输出字符串,不能进行格式转换。

  • puts()函数:向标准输出设备(屏幕、显示器)输出字符串并自行换行,因为将'\0'转换为了换行符'\n'
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char str[50] = "Hello world!"
    puts("Hello world!");
    puts(str);
    exit(0)
}
  • putchar()函数:把参数 c 指定的字符(一个无符号字符)输出到标准输出设备,其输出可以是一个字 符,可以是介于 0~127 之间的一个十进制整型数(包含 0 和 127,输出其对应的 ASCII 码字符),也可以是 用 char 类型定义好的一个字符型变量。
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    putchar('A');
    putchar('B');
    putchar('C');
    putchar('D');
    putchar('\n');
    exit(0);
}
  • fputc函数:也用于输出参数 c 指定的字符(一个无符号字符),与 putchar()区别在于,putchar()只能输出到标准输出设备,而fputc()不仅可以输出到标准输出设备,也可以是普通文件。

    • fput函数将字符输出到标准输出设备
      #include <stdio.h>
      #include <stdlib.h>
      int main(void)
      {
      fputc('A', stdout);
      fputc('B', stdout);
      fputc('C', stdout);
      fputc('D', stdout);
      fputc('\n', stdout);
      exit(0);
      }
      
      
    • fputc函数将字符输出到普通文件
      #include <stdio.h>
      #include <stdlib.h>
      int main(void)
      {
      FILE *fp = NULL;
      /* 创建一个文件 */
      fp = fopen("./new_file", "a");
      if (NULL == fp) {
      perror("fopen error");
      exit(-1);
      }
      /* 输入字符到文件 */
      fputc('A', fp);
      fputc('B', fp);
      fputc('C', fp);
      fputc('D', fp);
      fputc('\n', fp);
      /* 关闭文件 */
      fclose(fp);
      exit(0);
      }
      
  • fputs函数:用于输出一条字符串,可把字符串输出到指定的文件中,既可以是标准输出、标准错误设备,也可以是一个普通文件。int fputs(const char *s, FILE *stream);

    • fputs()输出到标准输出设备
    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
    fputs("Hello World! 1\n", stdout);
    fputs("Hello World! 2\n", stdout);
    exit(0);
    }
    
    
    • fputs()输出到普通文件
    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
    FILE *fp = NULL;
    /* 创建一个文件 */
    fp = fopen("./new_file", "a");
    if (NULL == fp) {
    perror("fopen error");
    exit(-1);
    }
    fputs("Hello World! 1\n", fp);
    fputs("Hello World! 2\n", fp);
    /* 关闭文件 */
    fclose(fp);
    exit(0);
    }
    

1.2 字符串输入

scanf()是格式化输入函数,C标准库提供的函数有gets()、getchar()、fgetc()、fgets().

  • gets()函数:用于从标准输入设备(譬如键盘)中获取用户输入的字符串char *gets(char *s);。s是指向字符数组的指针,用于存储字符串,返回值:成功返回指向s的指针,发生错误或读到空返回NULL。用户从键盘输入的数据首先会存到输入缓冲区,gets()函数从输入缓冲区中读取字符串存储到s指向的内存空间。gets()函数不检查缓冲区溢出。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    char str[100] = {0};
    char *ptr = NULL;

    ptr = gets(str);
    if (NULL == ptr)
        exit(-1);
    puts(str);

    exit(0);
}

注意:一般不建议使用gets()函数,因为程序中使用 gets()函数是非常不安全的,可能会出现 bug、出现不可靠性,gets()在某些意外情况下会导致程序陷入不可控状态。

  • gets()scanf()的区别:

    • gets()函数仅以回车换行符作为字符串的分隔符,也即允许字符串中出现空格、制表符等。而scanf()函数以%s格式输入的时候,将空格、换行符、TAB 制表符等都是作为字符串分割符,即分隔符前后是两个字符串,一个%s只能读取一个字符串
    • gets()会将回车换行符从输入缓冲区中取出来,然后将其丢弃,所以使用 gets()读走缓冲区中的字符串数据之后,缓冲区中将不会遗留下回车换行符。而scanf()。读走缓冲区中的字符串数据时,并不会将分隔符(空格、TAB 制表符、回车换行符等)读走将其丢弃,所以使用 scanf()读走缓冲区中的字符串数据之后,缓冲区中依然还存在用户输入的分隔符。
  • getchar()函数:用于从标准输入设备中读取一个字符(一个无符号字符)int getchar(void);getchar()函数也是从输入缓冲区读取字符数据,但只读取一个字符,包括空格、TAB 制表符、换行回车符等。

#include <stdio.h>
#include <stdlib.h> 

int main(void)
{
int ch;

ch = getchar();
printf("ch: %c\n", ch);
exit(0);
}
  • fgets()函数与gets()一样用于获取输入的字符串: char *fgets(char *s, int size, FILE *stream);。s是指向字符数组的指针,用于存储字符串,size是要读取的最大字符数,stream为文件指针。与gets()区别:
    • gets()只能从标准输入设备中获取输入字符串,而 fgets()既可以从标准输入设备获取字符串、也可以从一个普通文件中获取输入字符串。
    • fgets()可以设置获取字符串的最大字符数。
    • gets()会将缓冲区中的换行符'\n'读取出来、将其丢弃、将'\n'替换为字符串结束符'\0';fgets()也会将缓冲区中的换行符读取出来,但并不丢弃,而是作为字符串组成字符存在,读取完成之后自动在最后添加字符串结束字符'\0'。
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char str[100] = {0};

    printf("请输入字符串: ");
    fgets(str, sizeof(str), stdin);
    printf("%s", str);
    exit(0);
}
  • fgetc函数:与 getchar()一样,用于读取一个输入字符。
    int fgetc(FILE *stream);
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int ch;
    FILE *fp = NULL;

    /* 打开文件 */
    fp = fopen("./test_file", "r");
    if (NULL == fp) {
        perror("fopen error");
        exit(-1);
    }

    /* 从文件中输入一个字符 */
    ch = fgetc(fp);
    printf("%c\n", ch);

    /* 关闭文件 */
    fclose(fp);
    exit(0);
}

2、字符串长度

  • strlen()函数:C 语言函数库中提供了一个用于计算字符串长度的函数。size_t strlen(const char *s);返回值: 返回字符串长度(以字节为单位),字符串结束字符\0不计算在内。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char str[] = "Linux app strlen test!";

    printf("String: \"%s\"\n", str);
    printf("Length: %ld\n", strlen(str));
    exit(0);
}
  • sizeof是C 语言内置的操作符关键字,和strlen()函数区别如下:
    • strlen为C语言库函数
    • sizeof 仅用于计算数据类型的大小或者变量的大小,而strlen 只能以结尾为' \0 '的字符串作为参数。
    • 编译器在编译时就计算出了 sizeof 的结果,而 strlen必须在运行时才能计算出来;
    • sizeof 计算数据类型或变量会占用内存的大小,strlen 计算字符串实际长度。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char str[50] = "Linux app strlen test!";
    char *ptr = str;

    printf("sizeof: %ld\n", sizeof(str));
    printf("strlen: %ld\n", strlen(str));
    puts("~~~~~~~~~~");
    printf("sizeof: %ld\n", sizeof(ptr));
    printf("strlen: %ld\n", strlen(ptr));
    exit(0);
}

输出:
sizeof: 50
strlen: 22
~~~~~~~~~~~~~
sizeof: 8
strlen: 22

3、字符串拼接

C 语言函数库中提供了strcat()函数或strncat()函数用于将两个字符串连接(拼接)起来。

  • strcat()
    char *strcat(char *dest, const char *src);strcat()函数会把 src 所指向的字符串追加到 dest 所指向的字符串末尾,所以必须要保证 dest 有足够的存 储空间来容纳两个字符串,否则会导致溢出错误;dest 末尾的\0结束字符会被覆盖,src 末尾的结束字符\0会一起被复制过去,最终的字符串只有一个\0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char str1[100] = "Linux app strcat test, ";
    char str2[] = "Hello World!";

    strcat(str1, str2);
    puts(str1);
    exit(0);
}
  • strncat():strncat 可以指定源字符串追加到目标字符串的字符数量
    char *strncat(char *dest, const char *src, size_t n);

4、字符串拷贝

C 语言函数库中提供了strcpy()函数和strncpy()函数用于实现字符串拷贝。

  • strcpy:把 src(必须包含结束字符\0)指向的字符串复制(包括字符串结束字符\0)到 dest
    char *strcpy(char *dest, const char *src);

  • strncpy:把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 n 小于或等于 src 字符串长度(不包括结束字符的长度)时,则复制过去的字符串中没有包含结束字符\0;当 n 大于 src 字符串长度时,则会将 src 字。符串的结束字符\0也一并拷贝过去,必须保证 dest 指向的内存空间足够大,能够容纳下拷贝过来的字符串,否则会导致溢出错误。
    char *strncpy(char *dest, const char *src, size_t n);

5、内存填充

在编程中,经常需要将某一块内存中的数据全部设置为指定的值,譬如在定义数组、结构体这种类型变量时,通常需要对其进行初始化操作,而初始化操作一般都是将其占用的内存空间全部填充为 0。

  • memset函数用于将某一块内存的数据全部设置为指定的值
    void *memset(void *s, int c, size_t n); s:需要进行数据填充的内存空间起始地址。 c:要被设置的值,该值以 int 类型传递。 n:填充的字节数。 返回值:返回指向内存空间 s 的指针。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char str[100];

    memset(str, 0x0, sizeof(str));
    exit(0);
}

  • bzero()函数用于将一段内存空间中的数据全部设置为 0
    void bzero(void *s, size_t n);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char str[100];

    bzero(str, sizeof(str));
    exit(0);
}

6、 字符串比较

C 语言函数库提供了用于字符串比较的函数strcmp()strncmp()

  • strcmp()函数:
    int strcmp(const char *s1, const char *s2);
    返回值:
    • 如果返回值小于 0,则表示 str1 小于 str2
    • 如果返回值大于 0,则表示 str1 大于 str2
    • 如果返回值等于 0,则表示字符串 str1 等于字符串 str2

strcmp 进行字符串比较,主要是通过比较字符串中的字符对应的 ASCII 码值,strcmp 会根据 ASCII 编 码依次比较 str1 和 str2 的每一个字符,直到出现了不同的字符,或者某一字符串已经到达末尾

  • strncmp()函数:最多比较前 n 个字符
    int strncmp(const char *s1, const char *s2, size_t n);

7、字符串查找

C 语言函数库中提供了一些用于字符串查找的函数,包括strchr()strrchr()strstr()strpbrk()index()以及rindex()

  • strchr()函数:以查找到给定字符串当中的某一个字符,返回字符 c 第一次在字符串 s 中出现的位置(指针),如果未找到字符 c,则返回 NULL。
    char *strchr(const char *s, int c);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char *ptr = NULL;
    char str[] = "Hello World!";

    ptr = strchr(str, 'W');
    if (NULL != ptr) {
        printf("Character: %c\n", *ptr);
        printf("Offset: %ld\n", ptr - str);
    }

    exit(0);
}

输出:
Character: W
Offset: 6
  • strrchr()函数它同样表示在字符串中查找某一个字符,返回字符第一次在字符串中出现的位置,如果没找到该字符,则返回值 NULL,区别在于:,strrchr()函数在字符串中是从后到前 (或者称为从右向左)查找字符
    char *strrchr(const char *s, int c);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char *ptr = NULL;
    char str[] = "I love my home";

    ptr = strchr(str, 'o');
    if (NULL != ptr)
        printf("strchr: %ld\n", ptr - str);

    ptr = strrchr(str, 'o');
    if (NULL != ptr)
        printf("strrchr: %ld\n", ptr - str);

    exit(0);
}

输出:
strchr: 3
strrchr: 11
  • strstr()函数:在给定的字符串 haystack 中查找第一次出现子字符串 needle 的位置,不包含结束字符' \0 '。如果目标字符串 haystack 中包含了子字符串 needle,则返回该字符串首次出现的位置;如果未能找到子字符串 needle,则返回 NULL。
    char *strstr(const char *haystack, const char *needle);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char *ptr = NULL;
    char str[] = "I love my home";

    ptr = strstr(str, "home");
    if (NULL != ptr) {
    printf("String: %s\n", ptr);
    printf("Offset: %ld\n", ptr - str);
    }

    exit(0);
}

输出:
String: home
Offset: 10

8、字符串与数字互转

8.1 字符串转整形数据

C 函数库中提供了一系列函数用于实现将一个字符串转为整形数据,主要包括atoi()atol()atoll()以及strtol()strtoll()strtoul()strtoull()等,这些函数的区别在于: * 数据类型(int、long int、unsigned long等) * 不同进制表示的数字字符串

  • atoi()atol()atoll():将字符串分别转换为 int、long int 以及 long long 类型的数据。分别返回转换之后得到的 int 类型数据、long int 类型数据以及 long long 类型数据。转换时跳过前面的空格字符(如果目标字符串开头存在空格 字符)
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    printf("atoi: %d\n", atoi("500"));
    printf("atol: %ld\n", atol("500"));
    printf("atoll: %lld\n", atoll("500"));
    exit(0);
}
输出:
atoi:   500
atol:   500
atoll:  500
  • strtol()strtoll()函数可分别将字符串转为 long int 类型数据和 long long ing 类型数据,可以实现将多种不同进制数转换成整形。在 base=0 的情况下,如果字符串包含一个了“0x”前缀,表示该数字将以 16 为基数;如果包含的是 “0”前缀,表示该数字将以 8 为基数。 当 base=16 时,字符串可以使用“0x”前缀。
long int strtol(const char *nptr, char **endptr, int base);
long long int strtoll(const char *nptr, char **endptr, int base);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    printf("strtol: %ld\n", strtol("0x500", NULL, 16));
    printf("strtol: %ld\n", strtol("0x500", NULL, 0));
    printf("strtol: %ld\n", strtol("500", NULL, 16));
    printf("strtol: %ld\n", strtol("0777", NULL, 8));
    printf("strtol: %ld\n", strtol("0777", NULL, 0));
    printf("strtol: %ld\n", strtol("1111", NULL, 2));
    printf("strtol: %ld\n", strtol("-1111", NULL, 2));
    exit(0);
}

输出:
strtol: 1280
strtol: 1280
strtol: 1280
strtol: 511
strtol: 511
strtol: 15
strtol: -15
  • strtoul()strtoull()函数返回值类型是 unsigned long int和unsigned long long int
unsigned long int strtoul(const char *nptr, char **endptr, int base);
unsigned long long int strtoull(const char *nptr, char **endptr, int base);

8.2 字符串转整形数据

C 函数库中用于字符串转浮点型数据的函数有atof()strtod()strtof()strtold()

  • atof()将字符串转换为一个 double 类型的浮点数据 double atof(const char *nptr);

  • strtod()strtof()strtold()函数分别将字符串转换为 float 类型数据、double 类型数据、long double 类型数据。

double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
long double strtold(const char *nptr, char **endptr)

8.3 数字转字符串

数字转换为字符串推荐大家使用前面介绍的格式化 IO 相关库函数,譬如使用 printf()将数字转字符串、并将其输出到标准输出设备或者使用 sprintf()或 snprintf()将数字转换为字符串并存储在缓冲区中

9、给应用程序传参

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int i = 0;

    printf("Number of parameters: %d\n", argc);
    for (i = 0; i < argc; i++)
        printf(" %s\n", argv[i]);

    exit(0);
}

10、正则表达式

10.1、什么是正则表达式

正则表达式,又称为规则表达式,通常被用来检索、替换那些 符合某个模式(规则)的字符串,正则表达式描述了一种字符串的匹配模式,可以用来检查一个给定的字符串中是否含有某种子字符串、将匹配的字符串替换或者从某个字符串中取出符合某个条件的子字符串。

正则表达式其实也是一个字符串,该字符串由普通字符(譬如,数字 0~9、大小写字母以及其它字符)和特殊字符(称为“元字符”)所组成,由这些字符组成一个“规则字符串”,这个“规则字符串”用来表达对给定字符串的一种查找、匹配逻辑