C语言学习11-深入理解C语言字符串

📝 字符串的三种表示形式

1. 字符数组

char buf[128] = "hello";  // 在栈上分配的可修改内存

2. 字符指针

char* str_ptr = buf;  // 指向字符数组的指针

3. 字符串常量

const char* str_literal = "hello,world";  // 只读的字符串常量

重要说明:虽然都使用 char* 类型,但字符串常量实际上是 const char* 类型。

🔒 字符串常量详解

特性说明

const char* str = "hello,world";  // 正确:指向字符串常量
// str[0] = 'H';  // ❌ 错误!字符串常量是只读的

为什么是const char*?

  • 字符串常量存储在只读内存区(常量区)
  • 修改会导致未定义行为

为什么不需要长度信息

  • C风格字符串以 \0(空字符)作为结束标记
  • 遇到 \0 即认为字符串结束

🔄 字符串基本操作

1. 字符串遍历

#include <stdio.h>

void show_string(const char* str) {
    printf("遍历字符串: ");
    for (int i = 0; str[i] != '\0'; i++) {
        printf("%c ", str[i]);
    }
    printf("\n");
}

// 测试示例
int main() {
    show_string("Hello");
    return 0;
}

输出:

遍历字符串: H e l l o 

2. 字符串长度计算

#include <stdio.h>

int get_length(const char* str) {
    int count = 0;
    while (str[count] != '\0') {
        count++;
    }
    return count;
}

// 测试示例
int main() {
    char str1[128] = {'h', 'e', '\0', 'n', 'i', 'c', 'e'};  // 长度为2
    char str2[128] = {'\0', 'h', 'e', 'l', 'l', 'o'};       // 长度为0
    
    printf("str1长度: %d\n", get_length(str1));  // 输出: 2
    printf("str2长度: %d\n", get_length(str2));  // 输出: 0
    printf("'Hello'长度: %d\n", get_length("Hello")); // 输出: 5
    
    return 0;
}

3. 字符串复制

#include <stdio.h>

void string_copy(const char* src, char* dst) {
    int i = 0;
    while (1) {
        dst[i] = src[i];
        if (src[i] == '\0') break;
        i++;
    }
}

// 测试示例
int main() {
    char src[] = "hello";
    char dst[128];  // 确保目标缓冲区足够大
    
    string_copy(src, dst);
    printf("复制结果: %s\n", dst);
    
    // ❌ 这不是字符串复制!
    char buf[128] = "hello";
    char* p = buf;  // 这只是指针赋值,不是内容复制
    
    return 0;
}

复制注意事项

  • 目标缓冲区必须足够大
  • 必须复制结束符 \0
  • 指针赋值 ≠ 字符串复制

4. 字符串比较

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

int string_compare(const char* str1, const char* str2) {
    int i = 0;
    while (str1[i] != '\0' && str2[i] != '\0') {
        if (str1[i] < str2[i]) return -1;
        if (str1[i] > str2[i]) return 1;
        i++;
    }
    
    if (str1[i] == '\0' && str2[i] == '\0') return 0;
    if (str1[i] == '\0') return -1;
    return 1;
}

// 测试示例
int main() {
    char input[128];
    
    printf("请输入 'yes' 或 'no': ");
    scanf("%s", input);
    
    // ✅ 正确:使用strcmp或自定义比较函数
    if (string_compare(input, "yes") == 0) {
        printf("OK\n");
    } else {
        printf("Cancel\n");
    }
    
    // ❌ 错误:比较的是地址,不是内容
    // if (input == "yes") { ... }
    
    return 0;
}

比较规则

  • 逐个字符比较ASCII值
  • 所有字符相同且同时结束 → 相等
  • 发现不同字符 → 立即返回比较结果
  • 一个字符串是另一个的前缀 → 较短的小于较长的

🗑️ 字符串删除操作

基础删除方法(高成本)

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

// 从指定位置删除一个字符(需要移动后续所有字符)
void erase_char(char text[], int index) {
    int len = strlen(text);
    if (index < 0 || index >= len) return;
    
    for (int i = index; i < len; i++) {
        text[i] = text[i + 1];  // 后续字符前移
    }
}

// 测试示例
int main() {
    char text[] = "hello";
    printf("原始: %s\n", text);
    
    erase_char(text, 1);  // 删除 'e'
    printf("删除后: %s\n", text);  // 输出: hllo
    
    // 删除末尾字符(低成本)
    text[strlen(text) - 1] = '\0';
    printf("删除末尾后: %s\n", text);  // 输出: hll
    
    return 0;
}

例如:从一个字符串中间删除一个字符

char str[10] = "hello"
原字符串
删除 'e' , 后面的字符需要前移 - 结果:"hllo"

从字符串中间删除字符,这个操作是一个成本比较高的操作,每次都要移动很多数据。

高效删除方法:复制替代法

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

// 删除字符串中所有指定字符(高效版本)
void erase_all_chars(char text[], char char_to_delete) {
    int len = strlen(text);
    int new_index = 0;
    
    // 原地删除,不需要额外内存
    for (int i = 0; i < len; i++) {
        if (text[i] != char_to_delete) {
            text[new_index] = text[i];
            new_index++;
        }
    }
    text[new_index] = '\0';  // 添加新的结束符
}

// 需要额外内存的版本(适用于复杂删除规则)
void erase_all_chars_with_malloc(char text[], char char_to_delete) {
    int len = strlen(text);
    char* temp = (char*)malloc(len + 1);  // 临时缓冲区
    int new_index = 0;
    
    for (int i = 0; i < len; i++) {
        if (text[i] != char_to_delete) {
            temp[new_index] = text[i];
            new_index++;
        }
    }
    temp[new_index] = '\0';
    
    strcpy(text, temp);  // 复制回原数组
    free(temp);          // 释放临时内存
}

// 测试示例
int main() {
    char text[] = "China is a great country with a long history";
    printf("原始: %s\n", text);
    
    erase_all_chars(text, 'a');  // 删除所有 'a'
    printf("删除所有'a'后: %s\n", text);
    
    return 0;
}

输出:

原始: China is a great country with a long history
删除所有'a'后: Chin is  gret country with  long history

➕ 字符串插入操作

基础插入方法(高成本)

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

// 在指定位置插入字符(需要移动后续所有字符)
void insert_char(char text[], int index, char char_to_insert) {
    int len = strlen(text);
    
    // 检查边界和缓冲区大小
    if (index < 0 || index > len) return;
    
    // 从后向前移动字符,为新字符腾出空间
    for (int i = len; i >= index; i--) {
        text[i + 1] = text[i];
    }
    
    text[index] = char_to_insert;  // 插入新字符
}

// 测试示例
int main() {
    char text[128] = "hello";  // 确保缓冲区足够大
    
    printf("原始: %s\n", text);
    insert_char(text, 2, 'X');  // 在位置2插入'X'
    printf("插入后: %s\n", text);  // 输出: heXllo
    
    return 0;
}

高效插入方法:复制构建法

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

// 高效插入字符(使用临时缓冲区)
void efficient_insert(char text[], int index, char char_to_insert) {
    int len = strlen(text);
    char* temp = (char*)malloc(len + 2);  // 为新字符串分配空间
    
    // 复制前半部分
    for (int i = 0; i < index; i++) {
        temp[i] = text[i];
    }
    
    // 插入新字符
    temp[index] = char_to_insert;
    
    // 复制后半部分
    for (int i = index; i <= len; i++) {
        temp[i + 1] = text[i];
    }
    
    strcpy(text, temp);  // 复制回原数组
    free(temp);          // 释放临时内存
}

// 测试示例
int main() {
    char text[128] = "hello world";
    
    printf("原始: %s\n", text);
    efficient_insert(text, 5, ',');
    printf("插入后: %s\n", text);  // 输出: hello, world
    
    return 0;
}

💡 性能优化总结

操作成本分析

操作 时间复杂度 说明
访问单个字符 O(1) 直接通过索引访问
遍历字符串 O(n) 需要扫描整个字符串
删除末尾字符 O(1) 只需修改结束符
删除中间字符 O(n) 需要移动后续所有字符
插入字符 O(n) 需要移动后续所有字符

最佳实践建议

  1. 避免频繁的中间插入/删除:考虑使用链表等其他数据结构
  2. 批量操作使用复制法:一次性处理比多次移动更高效
  3. 确保缓冲区足够大:特别是进行插入操作时
  4. 使用标准库函数:如 strcpy, strcat, strcmp 等,它们经过高度优化
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容