2017-02-15 3 views
1

Хей, я пытался решить это школьное упражнение.Ошибка сегментации, вызванная realloc?

Напишите программу, которая сохраняет чтение в символьных строках и объединяет их (добавляет их в одну строку символов). конкатенация должна выполняться в функции, которая возвращает 1 в случае успеха или 0, если она не выполняется. для распределения памяти используйте только realloc!

У меня нет никакой ошибки при отладке программы, но когда я пытаюсь запустить программу, после того, как я вставляю строку, единственное, что появляется, это «Ошибка сегментации», что это может быть? Это код:

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

int cat(char **, char *); 

int main(void) 
{ 
    char string[51]; 
    char *output=NULL; 
    char choice; 
    do 
    { 
    printf("Please enter a string [<50 chars]: "); 
    fgets(string,50,stdin); 
    if(string[strlen(string)-1]=='\n') /* if newline was read as well */ 
     string[strlen(string)-1]=0;  /* discard it */ 
    if(cat(&output,string)) 
     printf("\n\nThe string now contains:\n%s\n",output); 
    else 
    { 
     printf("error: memory (re-)allocation failed!\n\n"); 
     return 1; /* exit with error */ 
    } 
    printf("Continue? (y/n) - "); 
    fgets(string,3,stdin); /* read input from keyboard - leave a safety buffer to account for read newline */ 
    choice=string[0]; /* use the first character from the previous read as the choice */ 
    } while(choice=='y' || choice=='Y'); 

    free(output); 
    return 0; 
} 

int cat(char **dest, char *src) 
{ 

    int i; 
    int length1=strlen(src); 
    int length2=strlen(*dest); 
    int length3=length1+length2; 
    *dest=(char*)realloc(NULL,sizeof(*src)); 
    printf("%p", *dest); 
    if(*dest==NULL) return 0; /* if allocation failed */ 
    for(i=0;i<=length3;i++) 
    { 
     if(i<=length1) 
     (*dest)[i]=(*dest)[i]; 
     else 
     (*dest)[i]=(src)[i]; 
    } 
    free(src); 
    return 1; 
} 
+0

Добро пожаловать на переполнение стека. Пожалуйста, найдите время, чтобы прочитать [The Tour] (http://stackoverflow.com/tour) и обратитесь к материалу из [Справочного центра] (http://stackoverflow.com/help/asking) о том, что и как вы можете спросите здесь. –

+0

Правильный инструмент для решения таких проблем - ваш отладчик.Перед тем, как просить о переполнении стека, вы должны пропустить свой код по очереди *. Для получения дополнительной информации, пожалуйста, прочтите [Как отлаживать небольшие программы (Эрик Липперт)] (https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). Как минимум, вы должны \ [изменить] ваш вопрос, чтобы включить пример [Минимальный, полный и проверенный] (http://stackoverflow.com/help/mcve), который воспроизводит вашу проблему, а также замечания, сделанные вами в отладчик. –

+0

Вы можете уменьшить ваши сравнения 'choice', используя' toupper() 'или' tolower() ', например:' toupper (выбор) == 'Y') '. –

ответ

4

Есть по крайней мере, 5 проблемы с вашим кодом:

1) Вы должны free только то, что выделенная себя в куче. Не стоит free(src), потому что то, что вы передаете в src, указывает на стек памяти (char string[51]; освобождается автоматически).

2) вы, вероятно, хотели перераспределить dest, и 3) вы хотели выделить память размером length3 (+1 нуль-терминатор).

*dest=(char*)realloc(*dest, length3 + 1); 

4) strlen(*dest) будет падать при *dest является NULL изначально.

int length2=(*dest)?strlen(*dest):0; 

5) Я не думаю, что ваша петля правильная. Он не будет конкатенировать строки, ваш расчет смещения выключен.

+0

Я сделал то, что вы сказали ... Но все же это дало мне ту же ошибку. –

+0

Назначив возвращаемое значение 'realloc()' непосредственно указателю на перераспределяемую память, вы рискуете потерять указатель на данные и получить утечка памяти. Если 'realloc()' fail, возвращается нулевой указатель. Вы должны сохранить возвращаемое значение во временном указателе, а затем проверить, чтобы оно было успешным. –

1

Начальная величина указателя output NULL. Однако внутри функции нет проверки того, что указатель равен NULL. Поэтому применение функции strlen к указателю приводит к неопределенному поведению.

Также вам необходимо зарезервировать еще один символ для нулевого окончания.

Память не перераспределяется правильно в функции. Кроме того, sizeof(*src) равен одному байту.

Это утверждение

if(i<=length1) 
    (*dest)[i]=(*dest)[i]; 

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

Вы не должны освобождать указатель src, поскольку он не указывает на динамически выделенную память.

Функция может выглядеть следующим образом, как показано в демонстрационной программе.

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

int cat(char **dest, const char *src) 
{ 
    size_t n = strlen(src) + (*dest == NULL ? 0 : strlen(*dest)); 

    char *tmp = realloc(*dest, n + 1); 
    int success = tmp != NULL; 

    if (success) 
    { 
     if (*dest == NULL) *tmp = '\0'; 
     *dest = tmp; 

     while (*tmp) ++tmp; 

     while ((*tmp++ = *src++)); 
    }  

    return success; 
} 

#define N 50 

int main(void) 
{ 
    char *output = NULL; 
    char choice = 'n'; 

    do 
    { 
     char string[N]; 


     printf("Please enter a string [<%d chars]: ", N); 
     fgets(string, sizeof(string),stdin); 

     string[strcspn(string, "\n")] = '\0'; 

     if (cat(&output, string)) 
     { 
      printf("\nThe string now contains:\n\"%s\"\n\n", output); 
     }   
     else 
     { 
      printf("error: memory (re-)allocation failed!\n\n"); 
      return 1; /* exit with error */ 
     } 

     printf("Continue? (y/n) - "); 
     fgets(string, 3, stdin); /* read input from keyboard - leave a safety buffer to account for read newline */ 
     choice = string[0]; /* use the first character from the previous read as the choice */ 
    } while (choice == 'y' || choice == 'Y'); 

    free(output); 

    return 0; 
} 

Его выход может выглядеть

Please enter a string [<50 chars]: Hi Stefano Feltre 

The string now contains: 
"Hi Stefano Feltre" 

Continue? (y/n) - y 
Please enter a string [<50 chars]: 

The string now contains: 
"Hi Stefano Feltre " 

Continue? (y/n) - y 
Please enter a string [<50 chars]: Let's learn C 

The string now contains: 
"Hi Stefano Feltre Let's learn C" 

Continue? (y/n) - n 
+0

@Stefano Feltre Смотрите демонстративную программу в своем ответе. –

+0

Mmmh ... Не удалось бы сделать это без использования макроса? Кроме того, для этого упражнения мне нужно сохранить функцию как: int cat (char ** dest, char * src) Я не могу изменить это. И я действительно не понимаю, зачем вам нужна переменная * tmp ... мы не можем напрямую использовать переменную * dest для realloc? Thx –

+0

@StefanoFeltre Макрос вводит имя вместо магического номера 50. Всегда лучше использовать именованные константы вместо магических чисел. Если ваш компилятор поддерживает массивы переменной длины, вы можете заменить его на константу. Например, const size_t N = 50; Вы должны объявить второй параметр с квалификатором const. Это контракт между функцией и клиентом, который использует функцию, в которой параметр не будет изменен внутри функции. Переменная tmp необходима, поскольку realloc может возвращать NULL. В этом случае значение dest будет потеряно. –

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