C语言字符串基础:从char数组到双指针反转算法

第一部分:char类型与字符串

1.1 char类型基础

老师强调 :char类型用于存放单个字符,如 char c = 'A';。字符常量用单引号包裹,这是最基础的字符单元。

复制代码
char c = 'A';      // 单个字符
char d = 'a';      // 字符常量用单引号

1.2 字符串的本质

老师强调C语言没有独立的字符串类型 。字符串本质上是以'\0'结尾的char类型数组。'\0'(空字符)是字符串的结束标识,缺了它程序就不知道字符串在哪结束。

复制代码
// ✅ 字符串:以'\0'结尾的字符数组
char s1[] = "hello";   // 实际存储: h e l l o \0
                       // 数组长度: 6(5个字符 + 1个'\0')

// ❌ 普通字符数组:没有'\0',不是字符串
char s2[3] = {'a','b','c'};  // 没有结束符,不是字符串

// ✅ 字符数组作为字符串(需手动加'\0')
char s3[4] = {'a','b','c','\0'};  // 是字符串

老师强调 :双引号包裹的才是字符串,如"hello"。单引号包裹的是单个字符,如'a'。字符串末尾隐含一个'\0',定义时需为其预留空间。

内存布局示例:

复制代码
char s[] = "hello";
索引 0 1 2 3 4 5
内容 h e l l o \0

老师强调:'\0'不显示但占一个字节,标志字符串终结。可类比成书本末尾的"完"字,没它系统就不知在哪停,会越界读内存。

1.3 字符串定义方式对比

写法 含义 是否字符串
char c = 'A'; 单个字符
char s[3] = {'a','b','c'}; 字符数组,无结束符
char s[4] = {'a','b','c','\0'}; 带结束符的字符数组
char s[] = "hello"; 字符串(自动加'\0')
char s[6] = "hello"; 字符串,长度6正好容纳
char s[10] = "hello"; 字符串,多余位置填'\0'

第二部分:字符串的输入输出

2.1 字符串输出

复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char s[] = "hello";
    
    // 方式1:printf + %s
    printf("%s\n", s);     // 输出 hello,遇到'\0'停止
    
    // 方式2:puts(自动换行)
    puts(s);               // 输出 hello 并换行
    
    // 方式3:putchar(输出单个字符)
    putchar(s[0]);         // 输出 h
    
    return 0;
}

老师强调printf("%s", s)遇到'\0'自动停止输出。puts()输出字符串后自动换行。putchar()输出单个字符,按下标取元素。

2.2 字符串输入

复制代码
#include <stdio.h>

int main() {
    char s[100];
    
    // 方式1:scanf(遇空格停止)
    scanf("%s", s);        // 输入 "hello world" → 只读取 "hello"
    printf("%s\n", s);
    
    // 方式2:带宽度限制(防溢出)
    scanf("%2s", s);       // 只读取前2个字符
    
    // 方式3:getchar(读取单个字符)
    char c = getchar();    // 读取一个字符
    printf("%c\n", c);
    
    // 方式4:scanf读取字符(%c前加空格跳过空白)
    scanf(" %c", &c);      // 跳过空格、换行等空白字符
    
    return 0;
}

老师强调scanf("%s")遇到空格、换行、Tab键 会立即停止,只能读取连续的非空白内容。输入"hello world"只会拿到"hello"。可用宽度限定如%2s限制最大长度,防止缓冲区溢出。

字符输入注意事项:

复制代码
// ❌ 问题:%c会读取上次输入残留的换行符
scanf("%c", &c);   // 可能读到'\n'

// ✅ 解决:%c前加空格跳过空白字符
scanf(" %c", &c);  // 忽略前导空白

第三部分:str系列函数

3.1 头文件

老师强调 :使用str系列函数必须包含头文件#include <string.h>,否则编译报错。

复制代码
#include <string.h>   // 必须包含

3.2 strcmp ------ 字符串比较

老师强调 :字符串比较不能用==运算符(比较的是地址),必须用strcmp()比较内容。

复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char a[] = "hello";
    char b[] = "world";
    
    // 方式1:使用strcmp
    if (strcmp(a, b) == 0) {
        printf("a == b\n");
    } else if (strcmp(a, b) > 0) {
        printf("a > b\n");
    } else {
        printf("a < b\n");
    }
    
    return 0;
}

strcmp返回值:

返回值 含义
0 两字符串相等
> 0 前者大于后者
< 0 前者小于后者

老师强调strcmp字典序比较,逐字符比较ASCII码值。

3.3 strcpy ------ 字符串复制

老师强调 :数组名是常量指针,不能被赋值,不能直接用a = b。必须用strcpy(dest, src)复制内容。

复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char a[20] = "hello";
    char b[] = "world";
    
    // ❌ 错误:数组名不能赋值
    // a = b;   // 编译报错
    
    // ✅ 正确:使用strcpy
    strcpy(a, b);      // 把b复制到a
    printf("%s\n", a); // 输出 world
    
    return 0;
}

老师强调strcpy(dest, src)将src的内容复制到dest,包括末尾的'\0'。确保dest空间足够大。

3.4 strcat ------ 字符串拼接

复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char a[20] = "hello";
    char b[] = "world";
    
    // 拼接:在a末尾追加b
    strcat(a, b);
    printf("%s\n", a);   // 输出 helloworld
    
    return 0;
}

3.5 strlen ------ 字符串长度

老师强调strlen()计算字符串有效字符个数,不包含'\0'

复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char s[] = "hello";
    
    // 方式1:strlen函数
    int len = strlen(s);    // len = 5(不包含'\0')
    printf("长度: %d\n", len);
    
    // 方式2:手动遍历
    int len2 = 0;
    for (int i = 0; s[i] != '\0'; i++) {
        len2++;
    }
    printf("手动计算: %d\n", len2);
    
    return 0;
}

老师强调strlensizeof不同------strlen算有效字符数(不含'\0'),sizeof算数组占用的总字节数(含'\0')。

表达式 结果("hello") 说明
strlen(s) 5 有效字符数,不含'\0'
sizeof(s) 6 数组总大小,含'\0'

第四部分:字符串遍历

4.1 遍历方式

复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char s[] = "hello";
    
    // 方式1:用'\0'判断结束
    for (int i = 0; s[i] != '\0'; i++) {
        printf("%c\n", s[i]);
    }
    
    // 方式2:用strlen获取长度
    int len = strlen(s);
    for (int i = 0; i < len; i++) {
        printf("%c\n", s[i]);
    }
    
    return 0;
}

老师强调 :遍历字符串的两种方式------用'\0'判断结束,或用strlen获取长度后循环。前者更通用,后者更直观。

第五部分:字符串反转(双指针法)

5.1 核心思路

老师强调 :字符串反转的本质是交换对称位置的字符。用双指针:left从0开始,right指向末尾字符(长度-1),两指针相向而行,交换所指字符,直到相遇或交叉。

反转过程图示:

复制代码
原始: h e l l o
      ↑       ↑
     left   right   → 交换h和o → o e l l h
      
      o e l l h
        ↑   ↑
       left right  → 交换e和h → o h l l e
      
      o h l l e
          ↑
       left/right  → 相遇,停止
      
结果: o l l e h

5.2 完整代码

复制代码
#include <stdio.h>
#include <string.h>

// 字符串反转函数
void reverse(char str[]) {
    int len = strlen(str);
    int left = 0;
    int right = len - 1;   // 指向最后一个有效字符,不是'\0'
    
    while (left < right) {
        // 交换左右字符
        char temp = str[left];
        str[left] = str[right];
        str[right] = temp;
        
        // 指针向中间移动
        left++;
        right--;
    }
}

int main() {
    char s[] = "hello";
    printf("反转前: %s\n", s);
    reverse(s);
    printf("反转后: %s\n", s);   // 输出 olleh
    
    return 0;
}

5.3 手动实现strlen

复制代码
// 不调用strlen,手动计算长度
int my_strlen(char str[]) {
    int len = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        len++;
    }
    return len;
}

// 反转时用自定义长度
void reverse_manual(char str[]) {
    int len = my_strlen(str);   // 不依赖库函数
    int left = 0;
    int right = len - 1;
    
    while (left < right) {
        char temp = str[left];
        str[left] = str[right];
        str[right] = temp;
        left++;
        right--;
    }
}

老师强调 :反转时**'\0'不参与运算**,它是字符串结束符,不能放进指针范围。right应指向len - 1(最后一个有效字符),而非len(指向'\0')。循环条件left < right,一旦相遇或交叉必须停止。

易错点:

复制代码
// ❌ 错误:right指向了'\0'
int right = strlen(str);   // 指向'\0'
while (left < right) { ... }  // 会把'\0'交换到前面

// ✅ 正确:right指向最后一个有效字符
int right = strlen(str) - 1;
相关推荐
佳児素花痴╮1 小时前
C++速通2
开发语言·c++·算法
麻瓜code1 小时前
【LeetCode】相交链表:双指针法,一次遍历找到交点
算法·leetcode·链表
zander2582 小时前
LeetCode 5. 最长回文子串
算法
hanlin033 小时前
刷题笔记:力扣第84题-柱状图中最大的矩形
笔记·算法·leetcode
青少儿编程课堂4 小时前
威佐夫博弈(双堆取子游戏)解析
c++·python·算法·bfs·信息学竞赛
辰烨chenye8 小时前
LeetCode Hot 100 题解 · 普通数组篇
算法·leetcode·职场和发展
hqyjzsb11 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
辰烨chenye11 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
微功夫信息技术11 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划