在C中反转字符串不会输出反转的行
我正在尝试反转C中的字符串。反向函数只是将给定位置(在for循环中)的字符分配给临时对象。 我在程序中看不到任何逻辑错误,并且使用以下命令在gcc 4.7.2下成功编译程序:
gcc -Wall -std=c99 reverse.c
要重新创建问题:
1.)运行程序并在shell中输入一个字符串
2.)完成输入后,按enter /和/或您的EOF信号。
问题是既没有打印原始字符串,也没有反转字符串。 这也是K&R第二版的练习,如果你完成了这个练习,我将不胜感激我的另一个解决方案。
我认为该错误是由缺少空字符引起的,着名的printf需要一个以空字符结尾的字符串来打印输入到cin。 getline函数将一个空字符分配给数组的末尾,当然空字符将是字符串中结束printf的第一个字符(因此不会打印字符/文字)。
#include #define MAXLINE 1000 int geline(char s[], int lim); void reverse(char line[], int length); int main() { char s[MAXLINE]; char t[MAXLINE]; int k, len; while ((len = getline(s, MAXLINE)) > 0) { if (len > 1) reverse(s, len); } printf("%s", s); return 0; } void reverse (char input[], int length) { char temp[MAXLINE]; int j = length; for (int i = 0; i < length; ++i, --j) { temp[i] = input[i]; input[i] = input[j]; input[j] = temp; } } int getline(char s[], int lim) { int c, i; for (i=0; (c=getchar()) != EOF && c!='\n'; ++i) s[i] = c; if (c== '\n') { s[i] = c; ++i; } s[i] = '\0'; return i; }
(我用-Wall -std=c99 -O3 -g
进行了编译, -g
允许使用gdb
)
以下是我注意到的事情以及解决它们的一些方法。 我试图密切关注你开始使用的样式(例如,我会将原型中的数组decls转换为指针,但这不是必需的)。
你的getline
原型错过了。
int getline(char s[], int lim);
在main
,你实际上并不需要k
, t[MAXLINE]
,你的printf
可能应该在循环中,所以你会看到每个单词都被反转。 请注意, printf
选择\n
,因为下面的getline
将换行符和EOF终止行转换为相同的东西(没有换行符):
int main() { char s[MAXLINE]; int len; while ((len = getline(s, MAXLINE)) > 0) { if (len > 0) reverse(s, len); printf("%s\n", s); } return 0; }
在上面, getline(s, MAXLINE)
可能是getline(s, sizeof(s) / sizeof(*s) - 1)
虽然再次注意fencepost错误(注意- 1
)。
reverse
函数可以大大改进,而不必考虑xor的疯狂跳过变量(虽然Daffra的例子很有趣,特别是它正确地停在中间)。 相反,拥有只是指向中途点的感觉是明显的胜利。 在它之间以及将temp
数组减少为临时字符之间,将保留您的常规样式。
void reverse (char input[], int length) { int max = length - 1; /* keep the final NUL in place */ for (int i = 0; i <= max / 2; ++i) { char ch = input[i]; input[i] = input[max - i]; input[max - i] = ch; } }
在上面的代码中, gcc -O3
可以对代码进行严格的修改,因此没有理由担心在每次循环测试等都会执行长除法。例如, gdb
报告i
自己会自动优化,这非常有趣。 首先编写好的,可读的代码,对编译器有一定的信心,稍后进行优化。
最后, getline
受益于针对lim
(CRITICAL!)的测试以及将换行符转换为NUL。
int getline(char s[], int lim) { int i, c; for (i=0; (i <= lim) && ((c=getchar()) != EOF) && (c != '\n'); ++i) s[i] = c; s[i] = '\0'; return i; /* return the index to the final NUL, same as length w/o it */ }
将MAXLINE
设置为10会暂时显示此版本相当优雅地处理超长行,将它们分成两个单独的行而不会丢失任何字符。
小心字符串以非常清楚地决定是要根据长度来描述它们,还是根据最后的NUL索引来描述它们。 这会影响你如何表达你的循环,限制,变量名等,显然混淆它们是fencepost错误的经典来源。
希望这可以帮助。
有两个逻辑错误:
-
int j = length;
应该是int j = length - 1;
-
temp[i] = input[i] ... input[j] = temp;
最后一个错误有两种方法:
- 将
temp
定义为单个char:char temp; ... temp = input[i]; input[i] = input[j]; input[j] = temp;
char temp; ... temp = input[i]; input[i] = input[j]; input[j] = temp;
- 在
temp
使用正确的索引:temp[i] = input[i]; input[i] = input[j]; input[j] = temp[i]
temp[i] = input[i]; input[i] = input[j]; input[j] = temp[i]
试试这段代码:
#include #define MAXLINE 1000 int geline(char s[], int lim); void reverse(char line[], int length); int main () { char s[MAXLINE]; char t[MAXLINE]; int k, len; while ((len = getline(s, MAXLINE)) > 0) { if (len > 1) reverse(s, len); } printf("%s", s); return 0; } void reverse (char input[], int length) { char temp; int j = length - 1; for (int i = 0; i < j; ++i, --j) { temp = input[i]; input[i] = input[j]; input[j] = temp; } } int getline (char s[], int lim) { int c, i; for (i=0; (c=getchar()) != EOF && c!='\n'; ++i) s[i] = c; if (c== '\n') { s[i] = c; ++i; } s[i] = '\0'; return i; }
int j = length - 1; // Thanks to @chux for (int i = 0; i < j; ++i, --j) { // or <= length / 2 char temp = input[i]; input[i] = input[j]; input[j] = temp;
不需要temp,也没有完全正确使用。
您需要两次交换值,这将在循环的后半部分恢复交换。 🙂
你的原型错过了't'( geline
)。 因此可能
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
被采取?
你可以使用这个快速function:
inline char * reverse(char *p) { char *save=p; char *q = p; while(q && *q) ++q; for(--q; p < q; ++p, --q) *p = *p ^ *q, *q = *p ^ *q, *p = *p ^ *q; return save ; }
请看一下这段代码:
#include #define MAXLINE 1000 int geline(char s[], int lim); void reverse(char line[], int length); int main() { char s[MAXLINE]; int len; while ((len = geline(s, MAXLINE)) > 1) { if (len > 1) { reverse(s, len); printf("%s", s); } } return 0; } void reverse (char input[], int length) { char temp; int j = length-1; for (int i = 0; i < j; ++i, --j) { temp = input[i]; input[i] = input[j]; input[j] = temp; } } int geline(char s[], int lim) { int c, i; for (i=0; (c=getchar()) != EOF && c!='\n'; ++i) s[i] = c; if (c== '\n') { s[i] = c; ++i; } s[i] = '\0'; return i; }
这里只需要进行2次更改,反之亦然。 内部function反向就这样做
int j = --length;
而不是这个:
input[j] = temp; //you should use input[j] = temp[i];