您已经有了一个很好的答案,但还有一些微妙的问题需要考虑。如果您使用面向行 输入法(fgets 或getline),则应删除'\n' 或'\r\n'(DOS/windows)行结尾读取并包含在fgets 或 getline 的原始行。 (这就是为什么您在原始文件的输出中有一个初始空行)。
删除行尾的一种简单方法是简单地用 nul-terminating 字符覆盖遇到的任一行尾中的第一个。为此,您的主程序逻辑如下所示:
while (fgets (str, MAXC, fp)) { /* read each line */
rmcrlf (str); /* trim \r or \n */
strrev (str); /* reverse string */
printf ("%s\n", str); /* output reverse */
}
您的rmcrlf(删除回车换行)可能如下所示:
/** stip trailing newlines and carraige returns by overwriting with
* null-terminating char. 's' is modified in place.
*/
void rmcrlf (char *s)
{
if (!s || !*s) return; /* validate not NUL and not empty */
char *p = strpbrk (s, "\r\n"); /* locate first line-ending char */
*p = 0; /* set to nul-terminating char */
}
(注意:您可以使用strlen(或指针和循环)来查找字符串的结尾并向后工作,但strpbrk 允许您在前向搜索'\n' 或'\r'方向而不需要找到终点并向后工作)
然后您可以以相同的方式反转您的字符串(但使用strrchr 来查找结尾而不是strlen)
/** strrev - reverse string 's' in place.
* The original string is not preserved.
* If 's' is not valid, no action taken.
*/
void strrev (char *s)
{
if (!s || !*s) { /* validate s not NUL and not empty */
printf ("strrev() error: invalid string\n");
return;
}
char tmp;
char *begin = s, *end = strrchr (s, 0) - 1;
while (end > begin) {
tmp = *end;
*end-- = *begin;
*begin++ = tmp;
}
}
您可以按如下方式将所有部分放在一起。这只是处理相同任务的另一种方法。注意:以下代码使用enum 而不是#define 来设置定义常量(只是为了显示替代方法)。另请注意:代码将从作为第一个参数给出的文件中读取(或默认情况下从stdin,如果没有给出文件名):
#include <stdio.h>
#include <string.h>
enum { MAXC = 256 };
void strrev (char *s);
void rmcrlf (char *s);
int main (int argc, char **argv) {
char str[MAXC] = "";
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file is open */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (str, MAXC, fp)) { /* read each line */
rmcrlf (str); /* trim \r or \n */
strrev (str); /* reverse string */
printf ("%s\n", str); /* output reverse */
}
if (fp != stdin) /* close file (if not stdin) */
fclose (fp);
return 0;
}
/** strrev - reverse string 's' in place.
* The original string is not preserved.
* If 's' is not valid, no action taken.
*/
void strrev (char *s)
{
if (!s || !*s) { /* validate s not NUL and not empty */
printf ("strrev() error: invalid string\n");
return;
}
char tmp;
char *begin = s, *end = strrchr (s, 0) - 1;
while (end > begin) {
tmp = *end;
*end-- = *begin;
*begin++ = tmp;
}
}
/** stip trailing newlines and carraige returns by overwriting with
* null-terminating char. 's' is modified in place.
*/
void rmcrlf (char *s)
{
if (!s || !*s) return;
char *p = strpbrk (s, "\r\n");
*p = 0;
}
示例输入
$ cat dat/strtorev.txt
abc def ghi jkl mno pqr
ABC DEF GHI JKL MNO PQR
输出
$ ./bin/strrev_line <dat/strtorev.txt
rqp onm lkj ihg fed cba
RQP ONM LKJ IHG FED CBA
(注意:正如 Johnathan 在评论中所问的那样,您可以如上所示反转该行,或者您可以反转每个单词(例如cba fed ihg...)确保您已正确说明您需要做什么,如果不是我们可以提供更多帮助)。
如果您有任何问题,请告诉我。