2013-04-19 2 views
4

Я читаю K & RC, в основном для того, чтобы чистить мои навыки C, и, пытаясь закодировать программу, чтобы отменить заданную строку, и у меня есть ошибка, которая наносит урон, что, хуже всего, я не могу отлаживать - и не знаю, что может быть причиной этого.Перестановка строк в C: Что я делаю неправильно?

Мой код выглядит следующим образом:

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

(Пожалуйста, простите отладочные, что засоряют код логики Кроме того, не стесняйтесь, чтобы исправить любую ошибку, вы можете увидеть, а также чувствовать себя свободно. внести предложения по его улучшению)

Теперь мой код работает (по большей части), но ошибка в том, что он копирует символы, которые я не вводил. Ниже приведены (смешные) Результаты двух тестовых прогонов:

Первый:

[email protected]:~/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 

(Обратите внимание на $)

и второе:

[email protected]:~/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 

Более точно изображен здесь:

The bug

Может кто-то более знающий и опытный, чем мне объяснить мне, что случилось с моим кодом, или, возможно, дать мне подсказку, почему я столкнулся это расстраивает ошибка?

ответ

2

Хорошо, аннотированный с ошибками, найденных выше плюс мой собственный ответ:

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

Вы возвращаете локальную переменную:

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

Локальная переменная reversed, которая была выделена в стеке, перестает существовать, как только функция reverse возвращается. Поэтому любая ссылка на него от main ведет к неопределенному поведению.

Чтобы исправить это, вы можете сделать одно из следующих действий:

  1. сделать функцию void и изменить массив ввода.

  2. Объявите массив reversed как статический, чтобы его время жизни изменялось на время жизни программы.

  3. Динамически выделить (а позже де-выделить) reversed

+0

Не могли бы вы разработать еще немного о том, почему это проблема? Я получил предупреждение от gcc, и, как вы можете видеть, оператор 'DEBUG' внутри этой функции также демонстрирует это поведение. – NlightNFotis

+2

Переменная, являющаяся локальной, не является проблемой. Это * автоматический * есть. – 2013-04-19 19:32:29

+0

Ребята, ребята, я не слепой, и я могу читать выход компилятора. Я знал, что это проблема, будь то маленькая или большая. ** Понимаете, у меня есть проблемы с оператором DEBUG внутри функции, прежде чем управление вернется в 'main'. ** – NlightNFotis

8

Всегда те же ошибки снова и снова ...

I.

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

Вы возвращая автоматический массив, который выходит за рамки, как только функция возвращает - неопределенное поведение.Введите reversed a static переменную, чтобы избежать этого (затем прочитайте ключевое слово static, прежде чем начинаете верить, что это волшебство).

II.

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

Потенциальный переполнение буфера и ошибка при вводе строк с пробелами в них. Изменить это на

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

III.

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

Другой буфер переполнен. В C массивы индексируются от 0.


Время, чтобы прочитать хорошую книгу C.

+1

Еще одна проблема: копия копирует строку [счетчик] в обратную [ размер-счетчик]. Таким образом, реверс [0] не будет установлен. Должно быть отменено [размер - 1 - счетчик]. – user295691

+0

@ user295691 Это решило мою проблему просто отлично. Я приглашаю вас отправить ответ на вопрос с тем, что вы сказали, и я также буду отмечать его как принятый. – NlightNFotis

3

Кроме пост codaddict и хороший объяснение Н2СО3, вы есть еще одна ошибка:

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

это приведет к индексу отказа, связанного. size = 10, затем size +1 =11. Значения индекса char char reversed: 0,1,2,3,...,10. Поэтому reversed[11] доставит вам неприятности.

+0

+1 Это хороший, который я не заметил вначале. Или, возможно, он просто проскользнул во время моих различных тестов. Ничего. – NlightNFotis

+0

@NlightNFotis: это исправит ваш оператор отладки внутри функции. – codaddict