Устранить ошибку сегментации в указателе на указатель на строку - PullRequest
1 голос
/ 07 декабря 2011

У меня ошибка сегментации, когда я хочу сохранить строку в динамическом массиве.

У меня есть программа, которая делает это:

Пользователь вставляет символ "s"
Программа входит в цикл и сохраняет строки в массиве (имя: cod).
Когдапользователь вставляет символ "t", он останавливается

После этого я сохраняю этот массив в первой позиции нового динамического массива (имя: vec).

Затем, если пользователь вставляет символ "s"снова
Программа входит в цикл и сохраняет строки в массиве.
Когда пользователь вставляет символ "t", он останавливается

После этого я сохраняю этот массив во второй позиции нового динамического массива..

и т. Д.


Это мой код:

int main () {

char Cod[30][11];
char tmp[11];
char ***vec;
int i = 0;


strcpy (tmp, "p");

vec = (char *** ) malloc (sizeof ( char *) );
vec[0] = (char ** ) malloc (sizeof ( char *) * 30);


do {

    scanf("%s", tmp);

    while( (strcmp (tmp, "p")) != 0){

        strcpy ( Cod[i] , tmp ); 

        scanf("%s", tmp);

        i++;
    }

    vec = (char ***) realloc (vec, sizeof ( char *) * (i + 1));
    vec[i + 1] = (char ** ) realloc (vec[i + 1], sizeof ( char *) * (30));
    vec[i-1] = (char **) Cod;
    scanf("%s", tmp);

}

while((strcmp (tmp, "s")) == 0);

    printf("%s", vec[0][0]);

return 0;

}

Это часть кода, которая работает:

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


int main(){

    char Cod[30][11];
    char tmp[11];
    int i = 0;


    strcpy (tmp, "p");


    do {

        scanf("%s", tmp);

        while( (strcmp (tmp, "p")) != 0){

            strcpy ( Cod[i] , tmp ); 

            scanf("%s", tmp);

            i++;
        }

        scanf("%s", tmp);

    }

    while((strcmp (tmp, "s")) == 0);

        printf("%s", Cod[0]);

return 0;

}

Ответы [ 4 ]

6 голосов
/ 07 декабря 2011

Я начал исправлять этот код, но вскоре понял, что в нем так много неправильного, что я не знаю, с чего начать.Так что вместо этого это оказался ответ code , вместо этого я прошу прощения, если он будет подробным и требовательным.

  • В C есть правилоговоря, что если вам нужно более двух уровней косвенного обращения к указателю, ваш код будет запутан и должен быть переписан (см. MISRA-C: 2004 17.5).

  • Это не имеет никакого смыслаиспользовать динамическое выделение памяти в этом случае, потому что при запуске программы вы уже знаете, что ни одна строка не будет длиннее 11 символов и не будет более 30 строк.Если это условие неверно, вам нужно написать более безопасный метод ввода, желательно с fgets (), который безопасен от переполнения буфера.Убедитесь, что входные данные не выходят за пределы массива "Cod".Вы можете выделить 30 * 11 = 330 байт статически, без совести.И это сделает код быстрее.

  • Нет смысла иметь 3 уровня косвенности для массива строк.Вы даже не используете динамическую память для хранения копии строк, вы просто распределяете указатели.Это не имеет никакого смысла вообще.Если вам нужна таблица поиска указателя, указывающая на Cod, а затем распределить ее статически, для нее потребуется только sizeof (char *) * 30 байт.

  • Как уже упоминалось, вы можете использовать realloc только для указателя, который ранее был malloc / calloc: ed.

  • Как уже упоминалось,никогда не вводите результат malloc / realloc в C. Это практика C ++.В Си это разрушает безопасность типов и скрывает ошибки совместимости типов.Здесь есть бесчисленное множество подробных обсуждений об этом, если вы хотите узнать подробности.

  • Что если вы не найдете "p" в пользовательской строке?Программа будет разрушена.

  • Не называйте переменные, которые влияют на основные функциональные возможности программы, на абстрактные вещи, такие как tmp, vec и т. Д. Tmp можно переименовать в input_buf или что-то подобное и т. Д.

  • Избегайте магических чисел в коде, используйте const или #define для констант длины массива.

  • Вы можете инициализировать строки в C, нет необходимостичтобы сделать это.char input_buf[INP_BUF_N] = "p";

  • Для поиска символа в строке используйте strchr ().

  • Вам не нужно иметь пользователяввод дважды одного и того же с помощью функции scanf () во внешнем цикле do-while, вероятно, это ошибка опечатки.

  • Вы не можете выполнять wild-typecast между статическим массивом массивов к указателю.к указателю.Это зависит от структуры того, на что указывает указатель на указатель.Потому что типичный динамический двумерный массив для тупых учебников (malloc (X sizeof (char ) ... malloc (Y * sizeof (char)) не будет выделять память рядом.на SO.

(вы можете размещать динамические двумерные массивы в смежной памяти с помощью указателей массива или с помощью "искажения", но это довольно сложные темы)

  • освободите () динамическую память, как только вы закончите, используя ее.

Как вы можете надеяться, разумный выбор здесь - переписать этот код с нуля.

2 голосов
/ 07 декабря 2011

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

char Cod[30][11];
char tmp[11];
char ***vec;
int i = 0;


strcpy (tmp, "p");
vec = (char***)malloc(sizeof(char *));
vec[0] = (char**)malloc(sizeof(Cod));


do {
    scanf("%s", tmp);        
    int j = 0;
    while(strcmp(tmp, "p")) {
        strcpy(Cod[j], tmp);
        scanf("%s", tmp);
        j++;
    }
    vec = (char ***)realloc(vec, sizeof(char *) * (i+1));
    vec[i] = (char **)malloc(sizeof(Cod));
    memcpy(vec[i], Cod, sizeof(Cod));//you need to copy results since next time the Cod will be rewritten
    scanf("%s", tmp);
    i++;
} while((strcmp(tmp, "s")) == 0);
2 голосов
/ 07 декабря 2011

для трех звезд

char ***vec;

вам нужно 3 malloc с (приведение в лучшем случае избыточно в C и может скрывать ошибку)

vec = malloc(sizeof *vec);
vec[0] = malloc(sizeof *vec[0]);
vec[0][0] = malloc(30 * sizeof *vec[0][0]); /* sizeof (char) is 1 by definition */
1 голос
/ 07 декабря 2011

В этих 2 строках:

vec = (char ***) realloc (vec, sizeof ( char *) * (i + 1));
vec[i + 1] = (char ** ) realloc (vec[i + 1], sizeof ( char *) * (30));

Если i = 1, то вы оставляете для "vec" i + 1 = 2 указателя.Во второй строке вы вызываете третью (vec [i + 1] = vec [2] - третий элемент в таблице размера 2).

...