2013-11-22 5 views
4

Я кодирую программу, которая принимает некоторые файлы в качестве параметров и печатает все обратные строки. Проблема заключается в том, что я получаю неожиданные результаты:Печатать строку, отмененную в C

Если я применяю его в файл, содержащий следующие строки

one 
two 
three 
four 

я получаю ожидаемый результат, но если файл содержит

september 
november 
december 

It возвращает

rebmetpes 
rebmevons 
rebmeceds 

И я не понимаю, почему это добавляет «S» в конце

Вот мой код

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

void reverse(char *word); 

int main(int argc, char *argv[], char*envp[]) { 
    /* No arguments */ 
    if (argc == 1) { 
     return (0); 
    } 

    FILE *fp; 

    int i; 
    for (i = 1; i < argc; i++) { 
     fp = fopen(argv[i],"r"); // read mode 

     if(fp == NULL) 
     { 
      fprintf(stderr, "Error, no file"); 
     } 

     else 
     { 
      char line [2048]; 
/*read line and reverse it. the function reverse it prints it*/ 
      while (fgets(line, sizeof line, fp) != NULL) 
       reverse(line); 
     } 
     fclose(fp); 
    } 

    return (0); 
} 

void reverse(char *word) 
{ 
    char *aux; 
    aux = word; 
    /* Store the length of the word passed as parameter */ 
    int longitud; 
    longitud = (int) strlen(aux); 

    /* Allocate memory enough ??? */ 
    char *res = malloc(longitud * sizeof(char)); 

    int i; 

    /in this loop i copy the string reversed into a new one 
    for (i = 0; i < longitud-1; i++) 
    { 
     res[i] = word[longitud - 2 - i]; 
    } 

    fprintf(stdout, "%s\n", res); 
    free(res); 
} 

(Примечание: некоторые код был удален для ясности, но она должна составить)

+0

Когда вы malloc для строки, измеряя длину, используя strlen(), вам нужен +1 для NULL-терминатора. – moeCake

ответ

4

Вы забыли прекратить вашу строку с \0 характером. При реверсии строка \0 станет вашим первым символом инвертированной строки. Во-первых выделить память для еще одного персонажа, чем вы выделили

char *res = malloc(longitud * sizeof(char) + 1); 

И попробовать этот

for (i = 0; i < longitud-1; i++) 
{ 
    res[i] = word[longitud - 2 - i]; 
} 
res[i] = '\0'; // Terminating string with '\0' 
+0

Да, но 'strlen' дает длину без конечного нуля, поэтому вы должны' malloc (longitud + 1) 'иметь место для' '\ 0''. ('Sizeof (char)' гарантированно равен 1.) Альтернативно, вы можете использовать модификатор точности в строке формата, чтобы выписать максимум символов longitud так: 'printf ("%. * S \ n ", longitud - 1, res); ' –

+0

@MOehm; Я пропустил 'char * res = malloc (longitud * sizeof (char));' line. Добавляем к моему ответу. – haccks

1

Я думаю, что я знаю эту проблему, и это немного странный вопрос.

Строки в C ноль завершены. Это означает, что строка «Привет!» в памяти фактически представлена ​​как 'H','i','!','\0'. Путь strlen и т. Д., Тогда знайте длину строки, подсчитывая количество символов, начиная с первого символа, до нулевого терминатора. Аналогично, при печати строки fprintf будет печатать все символы до тех пор, пока не ударит нулевой ограничитель.

Проблема заключается в том, что ваша функция reverse никогда не беспокоится о том, чтобы установить нулевой ограничитель в конце, который ему нужен, поскольку вы копируете символы в символ буфера по символу. Это означает, что он сбегает с конца выделенного буфера res и в неопределенную память, которая только что оказалась нулевой, когда вы ее ударили (malloc не дает никаких обещаний о содержимом выделенного вами буфера, просто чтобы он был достаточно большим). Вы должны получить другое поведение в Windows, так как я считаю, что в режиме отладки malloc инициализирует все буферы до 0xcccccccc.

Итак, что происходит, вы копируете сентябрь, обратный, в res. Это работает, как вы видите, потому что так получилось, что в конце есть ноль.

Затем вы освобождаете res, затем malloc снова. Опять же, случайно (и из-за некоторой сообразительности в malloc) вы получаете тот же самый буфер, который уже содержит «rebmetpes». Затем вы помещаете «ноябрь» в, наоборот, немного короче, поэтому ваш буфер теперь содержит «rebmevons».

Итак, исправление? Выделите еще один символ, это будет содержать нулевой ограничитель (char *res = malloc(longitud * sizeof(char) + 1);). После того, как вы измените строку, установите нулевой ограничитель в конце строки (res[longitud] = '\0';).

1

есть две ошибки там, то первое является то, что вам нужно один символ более выделяется (все символы в строке + 1 для терминатора)

char *res = malloc((longitud+1) * sizeof(char)); 

Второе, что вы должны прекратить действие Строка:

res[longitud]='\0'; 

Вы можете завершить строку перед вводом в цикл, потому что вы уже знаете размер строки назначения.

Обратите внимание, что с помощью calloc вместо malloc вам не нужно будет завершить строку в память получает alreay нулевой инициализируется

0

Спасибо, это решить мою проблему. Я читал что-то о «\ 0» в строках, но был не очень ясен, что теперь после прочтения всех ответов (все довольно хорошо). Спасибо всем за помощь.

Смежные вопросы