Skip to content

字符串

在C语言中,字符串是以空字符'\0'结尾的字符数组。本章将详细介绍C语言字符串的定义、操作和常用函数。

字符串基础

字符串的定义

c
/*
 * 字符串的定义方式
 */

#include <stdio.h>
#include <string.h>

int main(void)
{
    /* 方式1:字符数组初始化 */
    char str1[] = "Hello";  /* 自动添加'\0',大小为6 */
    
    /* 方式2:指定大小 */
    char str2[10] = "Hello";  /* 后面自动填充'\0' */
    
    /* 方式3:逐个字符初始化 */
    char str3[] = {'H', 'e', 'l', 'l', 'o', '\0'};
    
    /* 方式4:字符指针(指向字符串常量) */
    char *str4 = "Hello";  /* 字符串常量,不可修改 */
    
    /* 方式5:动态分配 */
    char *str5 = (char*)malloc(10);
    strcpy(str5, "Hello");
    
    /* 打印字符串 */
    printf("str1: %s\n", str1);
    printf("str2: %s\n", str2);
    printf("str3: %s\n", str3);
    printf("str4: %s\n", str4);
    printf("str5: %s\n", str5);
    
    /* 字符串大小 */
    printf("\nstr1的大小: %zu\n", sizeof(str1));      /* 6字节 */
    printf("str1的长度: %zu\n", strlen(str1));       /* 5个字符 */
    
    /* 字符数组 vs 字符指针 */
    str1[0] = 'h';  /* 可以修改 */
    printf("修改后str1: %s\n", str1);
    
    /* str4[0] = 'h'; */  /* 错误!字符串常量不可修改 */
    
    free(str5);
    
    return 0;
}

字符串的输入输出

c
/*
 * 字符串的输入输出
 */

#include <stdio.h>

int main(void)
{
    char name[50];
    
    /* 使用scanf输入 */
    printf("请输入姓名(不含空格): ");
    scanf("%s", name);  /* 注意:不需要& */
    printf("姓名: %s\n", name);
    
    /* scanf遇到空格会停止 */
    /* 输入 "Hello World" 只会读取 "Hello" */
    
    /* 使用fgets输入(推荐) */
    char sentence[100];
    getchar();  /* 清除缓冲区中的换行符 */
    
    printf("请输入一句话: ");
    fgets(sentence, sizeof(sentence), stdin);
    
    /* 去除末尾的换行符 */
    int len = 0;
    while (sentence[len] != '\0' && sentence[len] != '\n') {
        len++;
    }
    sentence[len] = '\0';
    
    printf("你输入的是: %s\n", sentence);
    
    /* 使用puts输出 */
    puts("使用puts输出");  /* 自动换行 */
    
    /* 使用fputs输出 */
    fputs("使用fputs输出", stdout);
    putchar('\n');
    
    return 0;
}

字符串函数

字符串长度和复制

c
/*
 * 字符串长度和复制函数
 */

#include <stdio.h>
#include <string.h>

int main(void)
{
    char src[] = "Hello, World!";
    char dest[50];
    
    /* strlen - 获取字符串长度(不包括'\0') */
    printf("strlen(src) = %zu\n", strlen(src));
    
    /* strcpy - 复制字符串 */
    strcpy(dest, src);
    printf("strcpy后: dest = %s\n", dest);
    
    /* strncpy - 复制指定长度 */
    char dest2[10];
    strncpy(dest2, src, 5);
    dest2[5] = '\0';  /* 手动添加结束符 */
    printf("strncpy后: dest2 = %s\n", dest2);
    
    /* strcat - 字符串连接 */
    char str1[50] = "Hello";
    char str2[] = " World";
    strcat(str1, str2);
    printf("strcat后: str1 = %s\n", str1);
    
    /* strncat - 连接指定长度 */
    char str3[20] = "Hello";
    strncat(str3, " World!!!", 6);
    printf("strncat后: str3 = %s\n", str3);
    
    /* 自定义strlen */
    size_t my_strlen(const char *s);
    printf("\n自定义strlen: %zu\n", my_strlen(src));
    
    return 0;
}

/* 自定义strlen函数 */
size_t my_strlen(const char *s)
{
    size_t len = 0;
    while (s[len] != '\0') {
        len++;
    }
    return len;
}

字符串比较

c
/*
 * 字符串比较函数
 */

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str1[] = "Hello";
    char str2[] = "Hello";
    char str3[] = "World";
    char str4[] = "hello";
    
    /* strcmp - 字符串比较 */
    /* 返回值:0表示相等,<0表示str1<str2,>0表示str1>str2 */
    printf("strcmp(str1, str2) = %d\n", strcmp(str1, str2));  /* 0 */
    printf("strcmp(str1, str3) = %d\n", strcmp(str1, str3));  /* <0 */
    printf("strcmp(str3, str1) = %d\n", strcmp(str3, str1));  /* >0 */
    
    /* 大小写敏感 */
    printf("strcmp(str1, str4) = %d\n", strcmp(str1, str4));  /* <0 */
    
    /* strncmp - 比较指定长度 */
    printf("strncmp(\"Hello\", \"Help\", 3) = %d\n", 
           strncmp("Hello", "Help", 3));  /* 0(前3个字符相同) */
    
    /* strcasecmp - 忽略大小写比较(非标准,POSIX) */
    /* printf("strcasecmp(str1, str4) = %d\n", strcasecmp(str1, str4)); */
    
    /* 使用示例 */
    if (strcmp(str1, str2) == 0) {
        printf("\nstr1和str2相等\n");
    }
    
    /* 自定义strcmp */
    int my_strcmp(const char *s1, const char *s2);
    printf("\n自定义strcmp: %d\n", my_strcmp("abc", "abd"));
    
    return 0;
}

int my_strcmp(const char *s1, const char *s2)
{
    while (*s1 && (*s1 == *s2)) {
        s1++;
        s2++;
    }
    return *(unsigned char*)s1 - *(unsigned char*)s2;
}

字符串查找

c
/*
 * 字符串查找函数
 */

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str[] = "Hello, World! Welcome to C!";
    
    /* strchr - 查找字符第一次出现的位置 */
    char *p = strchr(str, 'W');
    if (p != NULL) {
        printf("找到'W'在位置: %ld\n", p - str);
        printf("从'W'开始: %s\n", p);
    }
    
    /* strrchr - 查找字符最后一次出现的位置 */
    p = strrchr(str, 'o');
    if (p != NULL) {
        printf("最后一个'o'在位置: %ld\n", p - str);
    }
    
    /* strstr - 查找子串 */
    p = strstr(str, "World");
    if (p != NULL) {
        printf("找到\"World\"在位置: %ld\n", p - str);
    }
    
    /* strpbrk - 查找任意匹配字符 */
    p = strpbrk(str, "aeiou");
    if (p != NULL) {
        printf("第一个元音字母'%c'在位置: %ld\n", *p, p - str);
    }
    
    /* strspn - 计算匹配字符集的长度 */
    size_t len = strspn("123abc", "0123456789");
    printf("\n\"123abc\"中数字部分的长度: %zu\n", len);
    
    /* strcspn - 计算不匹配字符集的长度 */
    len = strcspn("abc123", "0123456789");
    printf("\"abc123\"中非数字部分的长度: %zu\n", len);
    
    /* strtok - 分割字符串 */
    char str_copy[] = "Hello,World,Welcome";
    char *token;
    
    printf("\n分割字符串:\n");
    token = strtok(str_copy, ",");
    while (token != NULL) {
        printf("  %s\n", token);
        token = strtok(NULL, ",");
    }
    
    return 0;
}

字符串转换

c
/*
 * 字符串转换函数
 */

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

int main(void)
{
    char str[] = "Hello World 123";
    
    /* 大小写转换 */
    printf("原字符串: %s\n", str);
    
    /* 转换为大写 */
    char upper[50];
    for (int i = 0; str[i]; i++) {
        upper[i] = toupper(str[i]);
    }
    upper[strlen(str)] = '\0';
    printf("大写: %s\n", upper);
    
    /* 转换为小写 */
    char lower[50];
    for (int i = 0; str[i]; i++) {
        lower[i] = tolower(str[i]);
    }
    lower[strlen(str)] = '\0';
    printf("小写: %s\n", lower);
    
    /* 字符串转数字 */
    char num_str[] = "12345";
    int num = atoi(num_str);  /* 字符串转int */
    printf("\natoi(\"12345\") = %d\n", num);
    
    long lnum = atol("1234567890");  /* 字符串转long */
    printf("atol(\"1234567890\") = %ld\n", lnum);
    
    double dnum = atof("3.14159");  /* 字符串转double */
    printf("atof(\"3.14159\") = %f\n", dnum);
    
    /* strtol - 更安全的转换 */
    char *end;
    long val = strtol("12345abc", &end, 10);
    printf("\nstrtol(\"12345abc\") = %ld\n", val);
    printf("未转换部分: %s\n", end);
    
    /* 不同进制转换 */
    val = strtol("FF", NULL, 16);  /* 十六进制 */
    printf("strtol(\"FF\", 16) = %ld\n", val);
    
    val = strtol("77", NULL, 8);   /* 八进制 */
    printf("strtol(\"77\", 8) = %ld\n", val);
    
    /* strtod - 字符串转double */
    double d = strtod("3.14abc", &end);
    printf("\nstrtod(\"3.14abc\") = %f\n", d);
    printf("未转换部分: %s\n", end);
    
    return 0;
}

字符处理函数

c
/*
 * 字符处理函数(ctype.h)
 */

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    char ch;
    
    printf("=== 字符分类函数 ===\n");
    
    /* isalpha - 是否是字母 */
    printf("isalpha('A'): %d\n", isalpha('A'));  /* 非0(真) */
    printf("isalpha('1'): %d\n", isalpha('1'));  /* 0(假) */
    
    /* isdigit - 是否是数字 */
    printf("isdigit('5'): %d\n", isdigit('5'));
    
    /* isalnum - 是否是字母或数字 */
    printf("isalnum('A'): %d\n", isalnum('A'));
    printf("isalnum('5'): %d\n", isalnum('5'));
    
    /* islower - 是否是小写字母 */
    printf("islower('a'): %d\n", islower('a'));
    
    /* isupper - 是否是大写字母 */
    printf("isupper('A'): %d\n", isupper('A'));
    
    /* isspace - 是否是空白字符 */
    printf("isspace(' '): %d\n", isspace(' '));
    printf("isspace('\\n'): %d\n", isspace('\n'));
    
    /* ispunct - 是否是标点符号 */
    printf("ispunct('.'): %d\n", ispunct('.'));
    
    /* iscntrl - 是否是控制字符 */
    printf("iscntrl('\\n'): %d\n", iscntrl('\n'));
    
    /* isxdigit - 是否是十六进制数字 */
    printf("isxdigit('F'): %d\n", isxdigit('F'));
    
    printf("\n=== 字符转换函数 ===\n");
    
    /* tolower - 转小写 */
    printf("tolower('A') = %c\n", tolower('A'));
    
    /* toupper - 转大写 */
    printf("toupper('a') = %c\n", toupper('a'));
    
    /* 实际应用:统计字符串中的字符类型 */
    char str[] = "Hello World 123!";
    int letters = 0, digits = 0, spaces = 0, others = 0;
    
    for (int i = 0; str[i] != '\0'; i++) {
        if (isalpha(str[i])) {
            letters++;
        } else if (isdigit(str[i])) {
            digits++;
        } else if (isspace(str[i])) {
            spaces++;
        } else {
            others++;
        }
    }
    
    printf("\n字符串 \"%s\" 中:\n", str);
    printf("字母: %d, 数字: %d, 空格: %d, 其他: %d\n", 
           letters, digits, spaces, others);
    
    return 0;
}

格式化字符串

c
/*
 * 格式化字符串函数
 */

#include <stdio.h>

int main(void)
{
    char buffer[100];
    int num = 42;
    float pi = 3.14159;
    
    /* sprintf - 格式化输出到字符串 */
    sprintf(buffer, "数字: %d, 圆周率: %.2f", num, pi);
    printf("sprintf结果: %s\n", buffer);
    
    /* snprintf - 限制输出长度(更安全) */
    snprintf(buffer, 10, "很长的字符串会被截断");
    printf("snprintf结果: %s\n", buffer);
    
    /* sscanf - 从字符串读取格式化输入 */
    char input[] = "姓名:张三 年龄:25";
    char name[20];
    int age;
    
    sscanf(input, "姓名:%s 年龄:%d", name, &age);
    printf("\nsscanf解析:\n");
    printf("姓名: %s\n", name);
    printf("年龄: %d\n", age);
    
    /* 解析日期 */
    char date[] = "2024-01-15";
    int year, month, day;
    
    sscanf(date, "%d-%d-%d", &year, &month, &day);
    printf("\n解析日期: %d%d%d\n", year, month, day);
    
    /* 解析IP地址 */
    char ip[] = "192.168.1.1";
    int a, b, c, d;
    
    sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d);
    printf("IP地址: %d.%d.%d.%d\n", a, b, c, d);
    
    return 0;
}

字符串应用实例

字符串反转

c
/*
 * 字符串反转
 */

#include <stdio.h>
#include <string.h>

/* 反转字符串 */
void reverse(char *str)
{
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        char temp = str[i];
        str[i] = str[len - 1 - i];
        str[len - 1 - i] = temp;
    }
}

/* 使用指针反转 */
void reverse_ptr(char *str)
{
    char *start = str;
    char *end = str + strlen(str) - 1;
    
    while (start < end) {
        char temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}

int main(void)
{
    char str1[] = "Hello";
    char str2[] = "World";
    
    printf("原字符串: %s\n", str1);
    reverse(str1);
    printf("反转后: %s\n", str1);
    
    printf("\n原字符串: %s\n", str2);
    reverse_ptr(str2);
    printf("反转后: %s\n", str2);
    
    return 0;
}

判断回文

c
/*
 * 判断回文字符串
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* 判断是否是回文 */
int is_palindrome(const char *str)
{
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        if (str[i] != str[len - 1 - i]) {
            return 0;  /* 不是回文 */
        }
    }
    return 1;  /* 是回文 */
}

/* 忽略大小写和空格判断回文 */
int is_palindrome_ignore(const char *str)
{
    char filtered[100];
    int j = 0;
    
    /* 过滤非字母字符并转小写 */
    for (int i = 0; str[i]; i++) {
        if (isalpha(str[i])) {
            filtered[j++] = tolower(str[i]);
        }
    }
    filtered[j] = '\0';
    
    return is_palindrome(filtered);
}

int main(void)
{
    char str[] = "上海自来水来自海上";
    
    printf("\"%s\" 是回文: %s\n", str, 
           is_palindrome(str) ? "是" : "否");
    
    char str2[] = "A man a plan a canal Panama";
    printf("\"%s\" 是回文(忽略大小写和空格): %s\n", str2, 
           is_palindrome_ignore(str2) ? "是" : "否");
    
    return 0;
}

小结

本章学习了:

  • 字符串定义:字符数组、字符指针、字符串常量
  • 字符串输入输出:scanf、fgets、puts、fputs
  • 字符串函数:strlen、strcpy、strcat、strcmp、strstr等
  • 字符处理函数:isalpha、isdigit、toupper、tolower等
  • 格式化字符串:sprintf、snprintf、sscanf
  • 字符串应用:反转、回文判断

下一章,我们将学习结构体,了解C语言结构体的定义和使用。