C 字符串反转
Posted
技术标签:
【中文标题】C 字符串反转【英文标题】:C String Reversed 【发布时间】:2013-10-27 22:19:56 【问题描述】:我正在编写一个简单的 c 程序来反转字符串,从 argv[1] 中获取字符串。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* flip_string(char *string)
int i = strlen(string);
int j = 0;
// Doesn't really matter all I wanted was the same size string for temp.
char* temp = string;
puts("This is the original string");
puts(string);
puts("This is the \"temp\" string");
puts(temp);
for(i; i>=0; i--)
temp[j] = string[i]
if (j <= strlen(string))
j++;
return(temp);
int main(int argc, char *argv[])
puts(flip_string(argv[1]));
printf("This is the end of the program\n");
基本上就是这样,程序编译和一切,但最后不返回临时字符串(只是空格)。一开始,当它等于字符串时,它会很好地打印温度。此外,如果我在 for 循环中逐个字符地执行 temp 的 printf ,则会打印出正确的临时字符串,即字符串 -> 反转。就在我尝试将其打印到标准输出(在 for 循环之后/或在 main 中)时,什么也没有发生,只打印空格。
谢谢
【问题讨论】:
我也在 Ubuntu 论坛上写过这篇文章,但认为这更像是一个一般性的编码问题。 你知道temp
和string
指向同一个内存位置吗?
别忘了接受 WhozCraig 的回答,这是做你想做的事的正确方法。干净整洁。
次要问题:不要在循环内长度不变的字符串上一遍又一遍地调用 strlen()。调用一次并存储结果。然后在循环中使用存储的值。
【参考方案1】:
您在尝试使用指针时朝着正确的方向前进。只要多想一点,你可能就会有它。下面是一个安全的实现:
#include <stdio.h>
char *flip_string(char *str)
char *lhs = str, *rhs = str;
if (!str || !*str || !*(str+1))
return str;
while (*++rhs); // rhs to eos
while (lhs < --rhs)
char tmp = *lhs;
*lhs++ = *rhs;
*rhs = tmp;
return str;
int main()
char test1[] = "Hello, World!";
char test2[] = "";
char test3[] = "1";
printf("%s, %s, %s\n", flip_string(test1), flip_string(test2), flip_string(test3));
return 0;
输出
!dlroW ,olleH, , 1
希望对你有帮助。
【讨论】:
可能值得指出char[]
和char*
之间的重要区别。在这种情况下,它会复制字符串,否则它将是未定义的行为。
我认为让flip_string
就地反转并返回参数很烦人。看过printf
行的人可能不会想到flip_string
实际上也修改它的论点。实现这个想法意味着您不再需要保留原始的str
指针,因此您可以使用它进行遍历,保存一个局部变量。
@FrerichRaabe 我同意。无论出于何种原因,这都是明显的要求。如果不是这样,我会按照你的描述去做;只需使用str
即可升级。当然,所有这些对于 mb-chars 来说都是完全失败的,例如,当然不限于 utf8。【参考方案2】:
您的函数似乎在执行“就地反转”,即它替换了内存中的给定字符串。这样做时,请确保不要将尾随零移动到前面。下面是函数的简单实现
#include <assert.h>
#include <string.h>
void flip_string(char *s)
assert(s);
char *t = strchr(s, '\0') - 1;
for (; s < t; ++s, --t)
char tmp = *s;
*s = *t;
*t = tmp;
函数断言它得到一个字符串(即不是空指针)并且内存是可写的。然后它设置一个t
指针指向字符串的最后一个字符——通过strchr
执行此操作而不是编写手动循环的好处是strchr
通常是一个高度优化的函数,它不会遍历单字节步骤中的字符串,而是一次考虑四个甚至更多字节。它也可以说更具表现力。
然后,主循环交换 s
和 t
引用的字符(即最初的第一个和最后一个字符),然后向前/向后移动指针直到它们相遇。
函数更简洁一点,因为它不需要保留传入的原始指针,而是可以直接修改s
。这是决定一个函数应该要么修改它的参数或返回一个新值的结果——但不能两者兼而有之。两者都做意味着你可以像这样调用函数
printf("%s", flip_string(s));
...这将完全掩盖 s
实际被修改的情况。
flip_string(s);
printf("%s", s);
在这方面更加明确。
【讨论】:
【参考方案3】:在这里,您显然希望 temp
成为除 string
之外的其他变量。但是你做的初始化会导致两个指针指向同一个位置。
你应该做的是:
char *flip_string(const char *string)
char *tmp = NULL;
size_t len = strlen(string);
int i = 0;
/*
* Don't forget that strlen() returns the length of the string
* **WITHOUT** counting the ending '\0' character.
* Thus, you have to add the extra space when you're allocating
*/
if (!(tmp = malloc(len + 1)))
printf("Allocation failed ...\n");
return NULL;
/*
* The newly created string must have an ending character
* Which is '\0'
*/
tmp[len] = '\0';
/*
* Here, you want to reverse the "true content" of your string.
* That is why you ignore the ending '\0' of the string by
* setting the upper bound to strlen (with a strict '<') **AND**
* it is also the reason a '- 1' just pops in the index choice.
*/
for(i = 0; i < len; i++)
tmp[i] = string[len - i - 1];
return tmp;
正如 WhozCraig 所强调的,有一种替代解决方案,它可以简单地修改参数字符串而不需要分配内存:
void flip_string(char *s)
size_t len = strlen(s);
char *p = s + len - 1;
while (s < p)
*p ^= *s;
*s ^= *p;
*p ^= *s;
p--;
s++;
注意XOR
技巧,以避免对交换的字符使用临时存储变量(^
是 C 中的XOR
运算符)
【讨论】:
你可以,但我没有。没有理由完全分配内存来反转标准的以零结尾的字符串。只需要两个指针和一个 while 循环(如果你想独立于strlen()
则需要两个)。
@WhozCraig,你应该发布它,你的回答应该比我的更有启发性(这里没有讽刺意味!)。
你们太棒了。谢谢!
另外,sizeof(char)
始终为 1。(对于 NULL 检查来说,这是一种奇怪的语法......)除此之外,我不喜欢 XOR 交换。
第二个版本有问题,使用了异或技巧,这里没有必要。以上是关于C 字符串反转的主要内容,如果未能解决你的问题,请参考以下文章