0

我正在尝试反转 C 中的字符串。 reverse 函数只是将给定位置(在 for 循环中)的字符分配给临时对象。我在程序中看不到任何逻辑错误,并且程序在 gcc 4.7.2 下使用以下命令成功编译:

gcc -Wall -std=c99 reverse.c

要重现问题:

1.) 运行程序并在你的 shell 中输入一个字符串

2.) 输入完成后,按 enter/and 或您的 EOF 信号。

问题是既没有打印原始字符串,也没有打印反向字符串。这也是 K&R 第二版的一个练习,如果你完成了这个练习,将不胜感激我的不同解决方案。

我认为该错误是由于缺少空字符引起的,著名的 printf 需要以空字符结尾的字符串才能将输入打印到 cin。getline 函数将空字符分配给数组的末尾,当然空字符将是字符串中的第一个字符,以结束 printf(因此不打印字符/文字)。

#include <stdio.h>

#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;
}
4

6 回答 6

2

有两个逻辑错误:

  • int j = length;应该int j = length - 1;
  • temp[i] = input[i] ... input[j] = temp;

最后一个错误有两种方法:

  • 定义temp为单个字符:char temp; ... temp = input[i]; input[i] = input[j]; input[j] = temp;
  • 在 中使用正确的索引temptemp[i] = input[i]; input[i] = input[j]; input[j] = temp[i]

试试这个代码:

#include <stdio.h>
#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;
}
于 2013-07-01T17:32:35.070 回答
1
 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);

被带走?

于 2013-07-01T17:18:09.627 回答
1

你可以使用这个快速功能:

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 ;
}
于 2013-07-01T19:33:23.993 回答
1

(我做了我的编译-Wall -std=c99 -O3 -g-g允许使用gdb

以下是我注意到的事情以及解决它们的一些方法。我已经尝试过与您开始使用的样式非常接近(例如,我会将原型中的数组 decls 转换为指针,但这不是必需的)。

您的getline原型缺少t.

int getline(char s[], int lim);

main中,您实际上并不需要k, t[MAXLINE],并且您printf可能应该在循环中,因此您会看到每个单词都被颠倒了。请注意,printf选择 a \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)再次出现,但要小心栅栏错误(注意- 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 的索引来描述它们。这会影响你如何表达你的循环、限制、变量名等,显然混淆它们是栅栏错误的典型来源。

希望这可以帮助。

于 2013-07-05T06:47:24.007 回答
0

请看一下这段代码:

#include <stdio.h>

#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;
}
于 2013-07-05T10:36:27.580 回答
0

这里只需要 2 处更改,它会做相反的事情。内部函数 reverse 只是这样做

int j = --length;

而不是这个:

input[j] = temp; //you should use 
input[j] = temp[i];
于 2018-03-09T06:41:37.193 回答