简体   繁体   English

在C中反转字符串不会输出反转行

[英]Reversing a string in C does not output the reversed line

I'm trying to reverse a string in C. The reverse function simply assigns the character at a given location (in a for loop) to a temp object. 我试图在C中反转字符串。reverse函数只是将给定位置(在for循环中)的字符分配给temp对象。 I cannot see any logic errors within the program, and the program compile successfully under gcc 4.7.2 with this command: 我在程序中看不到任何逻辑错误,并且使用以下命令在gcc 4.7.2下成功编译了程序:

gcc -Wall -std=c99 reverse.c

To recreate the problem: 重新创建问题:

1.) Run the program and enter a string into your shell 1.)运行程序,然后在外壳中输入一个字符串

2.) Once finished inputting, press enter/and or your EOF signal. 2.)输入完毕后,按Enter /和或EOF信号。

The problem is that neither the original string is printed, or the reversed string. 问题是既没有打印原始字符串,也没有反转字符串。 This is also an exercise from K&R second edition, if you have completed this exercise, a different solution to mine would be appreciated. 这也是K&R第二版的练习,如果您已经完成了该练习,则不胜感激。

I think the bug is caused by the absence of a null character, the famous printf requires a null terminated string to print input to cin. 我认为该错误是由于缺少null字符引起​​的,著名的printf需要以null结尾的字符串将输入输出到cin。 The getline function assigns a null character to the end of the array, surely the null character will be the first character in the string thereto ending the printf (and thus no character/literal is printed). 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;
}

There are two logic errors: 有两个逻辑错误:

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

There are two approaches for that last error: 对于最后一个错误,有两种方法:

  • Define temp as a single char: char temp; ... temp = input[i]; input[i] = input[j]; 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;
  • Use the correct index in temp : temp[i] = input[i]; input[i] = input[j]; input[j] = temp[i] 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]

Try this code: 试试这个代码:

#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;
}
 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 is not needed, and not entirely correctly used. temp是不需要的,并且不是完全正确使用的。

You are twice swapping the values, which restores the swap on the second half of the cycling. 您两次交换值,这将在循环的后半部分恢复交换。 :) :)


Your prototype misses a 't' ( geline ). 您的原型geline “ t”( geline )。 Hence maybe 因此,也许

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

is taken? 被采取?

you can use this fast 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 ;
}

(I did my compiling with -Wall -std=c99 -O3 -g , the -g to allow use of gdb ) (我使用-Wall -std=c99 -O3 -g进行了编译, -g允许使用gdb

Here are the things I noticed and some ways of addressing them. 这是我注意到的事情以及解决这些问题的一些方法。 I've tried to hew pretty closely to the style you started with (I would have converted the array decls in the prototypes to pointers, for example, but that's not necessary). 我尝试过与您开始使用的样式非常接近(例如,我会将原型中的数组decls转换为指针,但这不是必须的)。

Your getline prototype was missing the t . 您的getline原型缺少t

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

In main , you don't actually need k , t[MAXLINE] , and your printf should probably be in the loop so you'll see each word as it's reversed. main ,实际上并不需要kt[MAXLINE] ,并且printf应该在循环中,因此您会看到每个单词都被反转了。 Note that printf picks up a \\n , since the getline below converts both newline and EOF-terminated lines to the same thing (without newlines): 请注意, 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;
}

In above, the getline(s, MAXLINE) could have been getline(s, sizeof(s) / sizeof(*s) - 1) although again, be careful of fencepost errors (note the - 1 ). 在上面, getline(s, MAXLINE)可能是getline(s, sizeof(s) / sizeof(*s) - 1)尽管再次注意栅栏错误(请注意- 1 )。

The reverse function can be greatly improved without going over to the madness of xor to skip having a variable (although Daffra's example is interesting, especially in that it correctly stops in the middle). 可以极大地改善reverse功能,而不必担心xor跳过具有变量的疯狂(尽管Daffra的示例很有趣,尤其是它正确地停在中间)。 Instead, having the sense to just index up to the halfway point is a clear win. 取而代之的是,有意识地索引到中间点才是明显的胜利。 Between that and dropping reducing the temp array to just a temporary character, your general style is retained. 在这与删除将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;
    }
}

In the above gcc -O3 can do a serious workover on the code, so there's no real reason to worry that long division is going to be performed on every loop test, etc. For example, gdb reports that i itself gets optimized out automatically, which is pretty interesting. 在上面的代码中, gcc -O3可以对代码进行认真的检查,因此没有真正的理由担心在每个循环测试中都要进行长除法等。例如, gdb报告说i本身已经自动优化,这很有趣。 Write good, readable code first, have some faith in your compiler, optimize later. 首先编写良好的,易读的代码,对您的编译器有所信心,然后再进行优化。

And last, getline benefits from testing against lim (CRITICAL!) and and converting newlines into NULs. 最后, 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 */  
}

Setting MAXLINE to 10 temporarily shows that this version handles overlong lines fairly gracefully, splitting them into two separate ones without losing any of the characters. MAXLINE设置为10暂时表明该版本可以正常处理超长行,将它们分成两个单独的行而不会丢失任何字符。

Be careful with strings to very clearly decide whether you want to describe them in terms of length, or in terms of the index to the NUL at the end. 请小心使用字符串,以非常清楚地决定您是要使用长度来描述它们,还是要使用结尾处的NUL索引来描述它们。 This affects how you phrase your loops, limits, variable names, etc, and obviously confusing them is a classic source of fencepost errors. 这会影响您如何表达循环,限制,变量名称等的方式,并且很明显地使它们混淆是栅栏错误的经典来源。

Hope this helps. 希望这可以帮助。

Please have a look at this code: 请看下面的代码:

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

Only 2 changes needed here, and it will do the reverse fine. 此处仅需要进行2次更改,它将起到相反的作用。 Inside function reverse just do this 内部功能反向只是这样做

int j = --length;

Instead of this: 代替这个:

input[j] = temp; //you should use 
input[j] = temp[i];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM