简体   繁体   中英

String reversal in C: What is it I am doing wrong?

I am amidst reading K&R C, mainly to brush my C skills, and while attempting to code a program to reverse a given string, and I have a bug that plagues, which, worst of all, I am unable to debug - nor have a clue what might be the cause of it.

My code is the following:

#include <stdio.h>
#include <string.h>

char * reverse(char *string);

int main(int argc, char *argv[])
{
    printf("Please input a string: \t");

    char string[256];

    scanf("%s", string);

    char *reversed = reverse(string);

    printf("The reversed string is %s\n", reversed);

    return 0;
}

char * reverse(char string[])
{
    int size = strlen(string);
    printf("DEBUG: The size of the string that we got as input was: %d\n", size);
    int counter;
    char reversed[size + 1];

    for(counter = size - 1; counter >= 0; counter--) {
        reversed[size - counter] = string[counter];
        printf("DEBUG: The character copied now was %c and was at index %d\n", string[counter], counter);
    }

    reversed[size + 1] = '\0';

    printf("DEBUG: The reversed string is %s\n", reversed);

    return reversed;
}

(Please forgive the debug statements that litter the code logic. Apart from that, feel free to correct any mistake you might see, and also feel free to make suggestions to improve it)

Now, my code is working (for the most part) but the bug is that it copies characters that I have not input. Below are the (funny) results of two test runs:

The first one:

nlightnfotis@crunchbang:~/SoftwareExperiments$ ./reverse
Please input a string:  fotis
DEBUG: The size of the string that we got as input was: 5
DEBUG: The character copied now was s and was at index 4
DEBUG: The character copied now was i and was at index 3
DEBUG: The character copied now was t and was at index 2
DEBUG: The character copied now was o and was at index 1
DEBUG: The character copied now was f and was at index 0
DEBUG: The reversed string is $sitof
The reversed string is $sitof

(Notice the $ )

and the second one:

nlightnfotis@crunchbang:~/SoftwareExperiments$ ./reverse
Please input a string:  lol
DEBUG: The size of the string that we got as input was: 3
DEBUG: The character copied now was l and was at index 2
DEBUG: The character copied now was o and was at index 1
DEBUG: The character copied now was l and was at index 0
DEBUG: The reversed string is lol
The reversed string is lol

More accurately depicted here:

错误

Could someone more knowledgeable and experienced than me explain to me what's wrong with my code, or maybe give me a hint as to why I am facing this frustrating bug?

You are returning a local variable:

char * reverse(char string[]) {    
  char reversed[size + 1];
  ....
  return reversed;
}

The local variable reversed which was allocated on the stack, ceases to exist once the function reverse returns. So any reference to it from main leads to undefined behavior.

To fix this you can do either of the following:

  1. Make the function void and modify the input array.

  2. Declare the array reversed as static so that its lifetime changes to the lifetime of the program.

  3. Dynamically allocate (and later de-allocate) reversed

Always the very same errors, over and over...

I.

char reversed[size + 1];
// ...
return reversed;

You're returning an automatic array, which is out of scope as soon as the function returns - undefined behavior. Make reversed a static variable to avoid this (then read up on the static keyword before you start to believe it's magic).

II.

char string[256];
scanf("%s", string);

Potential buffer overrun and bug when entering strings with spaces in them. Change this to

fgets(string, sizeof(string), stdin);

III.

char reversed[size + 1];
// ...
reversed[size + 1] = '\0';

Another buffer overrun. In C, arrays are indexed from 0.


Time to read a good C book.

Besides codaddict's post and H2CO3's nice explanation, you have one more error:

 char reversed[size + 1];
 reversed[size + 1] = '\0';

this will result in index of out bound. say size = 10 , then size +1 =11 . index values of char array reversed are 0,1,2,3,...,10 . Therefore, reversed[11] will be get you in trouble.

Okay, annotated with the errors found above plus my own answer:

char * reverse(char string[])
{
    int size = strlen(string);
    printf("DEBUG: The size of the string that we got as input was: %d\n", size);
    int counter;

    /* BUGBUG: You are using a stack variable to store the return string.
     * char *reversed = malloc(sizeof(char) * (size + 1))
     * to allocate a string that can be returned safely.
     */
    char reversed[size + 1];

    for(counter = size - 1; counter >= 0; counter--) {
        /* BUGBUG: You are setting the wrong char in "reversed", it should be
         * reversed[size - 1 - counter].  You want the "size - 1" char from the original
         * to be copied to the 0 position of the reversed
         */
        reversed[size - counter] = string[counter];
        printf("DEBUG: The character copied now was %c and was at index %d\n", string[counter], counter);
    }

    /* BUGBUG: You are setting the null character one past the end of the string.
     * Here you want reversed[size], which with 0-indexing is the size+1'st
     * character.
     */
    reversed[size + 1] = '\0';

    printf("DEBUG: The reversed string is %s\n", reversed);

    /* BUGBUG: Just to stress this -- you cannot expect this to work; that it
     * does so is accidental because the call stack is not cleaned.  If the calling
     * function called another function (say printf) then the printf is likely to 
     * overwrite the contents of reversed.
     */
    return reversed;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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