C语言字符串逆序反转详解:双指针与非递归/递归实现

沈知远
沈知远
发布时间:2026-10-15 | 4人浏览过
原创

在C语言开发中,字符串逆序反转是考察指针与内存操作的经典场景。通过双指针从两端向中间逼近并交换元素,可以高效实现原地翻转。本文将对比非递归的双指针遍历法与递归调用法,重点剖析形参传值导致的长度计算差异及栈帧管理机制。

双指针法核心逻辑

字符串逆序的本质是将首尾字符进行配对交换。通过定义两个指针(或下标),一个指向头部,另一个指向尾部,在满足条件时执行交换操作并向中心移动,直至相遇。

第1步:基于指针的直接交换

目的:利用指针直接操作内存地址,演示最基础的逆序逻辑。
入口:包含 <stdio.h> 和 <string.h>。
动作:声明字符数组,获取长度后设置首尾指针进行 while 循环交换。

#include<stdio.h>
#include<string.h> 
 
void rec(char* arr)
{
	int len = strlen(arr);
	printf("字符串长度len = %d\n", len);
	char* p1 = arr; // 首指针
	char* p2 = &arr[len - 1]; // 尾指针
	while (p1 < p2)
	{
		char temp = *p1;
		*p1 = *p2; // 正向赋值
		*p2 = temp; // 逆向回写
		p1++; // 指针后移
		p2--; // 指针前移
	}
} 
 
int main()
{
	char arr[] = "hello world";
	rec(arr); 
	printf("逆序之后输出为:%s\n", arr);
	return 0;
}

完成判断:执行后原字符串内容被改变为倒序排列。注意:因为传入的是内存地址,修改会直接影响原始数据,若需保护源数据应先拷贝一份。

字符串逆序的常见实现方式

在实际编程中,通常使用数组下标替代指针进行操作,或者将逻辑封装为函数。需注意区分“逆序存储”与“逆序打印”,前者改变内存中的 str[0] 到 str[n-1],后者仅调整输出顺序。

第2步:非递归下标遍历

准备:定义定长字符数组或使用动态输入。对于用户输入的变长字符串,必须预留足够空间如 char arr[101] 防止越界。
动作:

  • 计算有效长度:输入静态常量时使用 sizeof(arr)/sizeof(arr[0])-1;读取输入后务必使用 strlen(arr)。
  • 设定左右索引:`left = 0`, `right = len - 1`。
  • 执行循环:当 left < right 时交换 arr[left] 与 arr[right] 并步进索引。
#include <stdio.h>
#include <string.h>
// 以固定数组为例
int main()
{
	char arr[] = "abcdef";
	int sz = sizeof(arr) / sizeof(arr[0]); // 包含 '\0',总数6个
	int left = 0;
	int right = sz - 2;   // 减2避开末尾的结束符 '\0'
	while (left < right)
	{
		char tmp = arr[left];
		arr[left] = arr[right];
		arr[right] = tmp;
		left++;
		right--;
	}
	printf("%s", arr); // 结果 fedcba
	return 0;
}

第3步:封装为函数时的避坑指南

当将逆序逻辑封装为 `void reverse(char arr[])` 时,最大的难点在于计算长度。

  • 错误做法:直接使用 `sizeof(arr)/sizeof(arr[0])`。因为在函数内部,数组名退化为指针,其大小仅为4字节(32位)或8字节(64位)。这会导致计算结果为0或1,无法正确运行。
  • 正确做法:始终使用 strlen(arr) 获取字符串的实际字符数。在函数内,形参 char arr[] 本质等价于 char *arr。
// 正确的函数封装示例
void reverse(char arr[])
{
	int left = 0;
	int right = strlen(arr) - 1;      // 只能用库函数求长度
	while (left < right)
	{
		char tmp = arr[left];
		arr[left] = arr[right];
		arr[right] = tmp;
		left++;
		right--;
	}
}

递归实现字符串逆序

递归解法利用函数调用栈的特性,层层深入并在回溯过程中恢复元素位置。以下是两种典型的递归思路。

第4步:方法一 —— 截断递归法

原理:每次递归都将当前最后一个字符暂存,并将字符串末尾强制置零,从而形成一个短一截的新子串进行递归。待子串处理完毕后再回溯,将暂存的字符填回末尾。

  1. 保存首位字符到临时变量。
  2. 将末位字符移到首位。
  3. 将末位覆盖为 '\0',缩小问题规模。
  4. 对剩余部分递归调用。
  5. 在回溯时,将暂存的首位字符填入末位。
#include <stdio.h>
#include <string.h>
void reverse(char str[])
{
	char tmp = *str;
	int len = strlen(str);
	if (len == 0) return;
	*str = *(str + len - 1);
	*(str + len - 1) = '\0';
	if (strlen(str + 1) >= 2)  // 中间元素无需交换
	{
		reverse(str + 1);
	}
	*(str + len - 1) = tmp; // 回溯还原
}
int main()
{
	char arr[101] = { 0 };
	scanf("%s", arr);
	reverse(arr);
	printf("%s\n", arr);
	return 0;
}

第5步:方法二 —— 指针范围递归法

原理:更直观地传递左右边界参数,符合迭代法的思维,但在递归框架下执行。

  1. 接收左边界 `left` 和右边界 `right`。
  2. 交换两端的值。
  3. 以 left+1 和 right-1 为参数继续递归。
  4. 基准条件:`left >= right` 时停止。
#include <stdio.h>
#include <string.h>
void reverse(char str[], int left, int right)
{
	if (left < right)
	{
		char tmp = str[left];
		str[left] = str[right];
		str[right] = tmp;
		reverse(str, left + 1, right - 1); // 递归缩减范围
	}
}
int main()
{
	char arr[101] = { 0 };
	scanf("%s", arr);
	reverse(arr, 0, strlen(arr)-1);
	printf("%s\n", arr);
	return 0;
}

总结与注意事项

  • 长度计算的陷阱:仅在静态初始化的代码块中使用 `sizeof` 计算有效长度安全,进入函数后务必改用 `strlen`。
  • 数组定义:用于接收键盘输入时,字符数组必须指定明确的大小(如 [101]),否则极易发生缓冲区溢出。
  • 内存保护:所有上述例子均为原地修改(In-place)。如果需要保留原字符串,请先调用 strcpy 创建副本。
以上就是C语言字符串逆序反转的详细技术要点,更多关于C语言指针与数组操作的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表