Почему мой код выдает ошибку сегментации? - PullRequest
0 голосов
/ 30 января 2019
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void concatena(char *, char *, char *);
void conta_consonanti(char [], int *);
void copy_string(char [], char [ ], int);

int main(void) {
    char *input1, *input2, *output;
    input1 = "sdaeteruiop";
    input2 = "eiyearteoiana";
    concatena(input1, input2, output);
    printf("%s\n", output);
    free(output);
    return 0;
}

void concatena(char *input1, char *input2, char *output) {
    int num_cons1 = 0, num_cons2 = 0, dim_input1, dim_input2;
    conta_consonanti(input1, &num_cons1);
    conta_consonanti(input2, &num_cons2);
    if (num_cons1 < num_cons2) {
        dim_input1 = strlen(input1) + strlen(input2);
        output = malloc(dim_input1 * sizeof(char));
        copy_string(output, input1, 0);
        copy_string(output, input2, strlen(input1));
    } else if (num_cons2 < num_cons1) {
        dim_input2 = strlen(input2) + strlen(input1);
        output = malloc(dim_input2 * sizeof(char));
        copy_string(output, input2, 0);
        copy_string(output, input1, strlen(input2));
    }
}

void conta_consonanti(char vect[], int *num_cons) {
    int dim = strlen(vect), i;
    for (i = 0; i < dim; i++)
        if (vect[i] != 'a' && vect[i] != 'e' && vect[i] != 'i' && vect[i] != 'o' && vect[i] != 'u')
            *num_cons++;
}

void copy_string(char output[], char input [ ], int offset) {
    int dim, i;
    dim = strlen(input);
    for (i = 0; i < dim; i++) {
        output[offset] = input[i];
        offset++;
    }
}

Почему мой код вызывает ошибку сегментации?

Программа должна объединить две строки и сохранить результирующую строку в output, но при этом возникает ошибка сегментации.Почему?

Строка с меньшим количеством согласных записывается первой.

Ответы [ 3 ]

0 голосов
/ 30 января 2019

Вы пытаетесь освободить output в основном, пока ему не назначено значение.Назначение в concatena не возвращается в main.Было бы более целесообразно вернуть выделенный буфер из concatena и присвоить его output, а затем очистить в конце.

0 голосов
/ 30 января 2019

В вашем коде несколько проблем:

  • Вы передаете неинициализированный указатель для массива назначения (третий аргумент) concatena.API неверен: вместо этого вы должны заставить concatena возвращать указатель на вновь выделенный массив в качестве возвращаемого значения.Текущая реализация перезаписывает третий аргумент output, и это выделенное значение никогда не возвращается вызывающей стороне.C не имеет понятия output аргументов, вы можете передать указатель на указатель output вызывающего, с типом char **, но гораздо проще просто использовать возвращаемое значение.
  • Распределение, выполняемое concatena, неверно: вы должны выделить дополнительный байт для нулевого терминатора, а sizeof(char) равно 1 по определению:

    output = malloc(dim_input1 + 1);
    
  • conta_consonanti тоже неверно: при увеличении числа, на которое указывает num_cons, должно быть написано ++*num_cons или (*num_cons)++.*num_cons++; увеличивает указатель, а не значение, на которое указывает.Кроме того, как прокомментировал Том Рэндалл, число согласных не обязательно совпадает с числом не гласных, поскольку строка может содержать не буквы.Также вы учитываете все заглавные буквы как согласные, что тоже кажется неправильным.

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

  • copy_string не устанавливает нулевой терминатор в целевом буфере.Либо установите его там, либо установите вручную в concatena.

Вот исправленная (и упрощенная) версия:

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

char *concatena(const char *s1, const char *s2);
int conta_consonanti(const char *vect);
void copy_string(char *output, const char *intput);

int main(void) {
    const char *input1 = "sdaeteruiop";
    const char *input2 = "eiyearteoiana";
    char *output = concatena(input1, input2);
    printf("%s\n", output);
    free(output);
    return 0;
}

char *concatena(const char *input1, const char *input2) {
    int len1 = strlen(input1);
    int len2 = strlen(input2);
    int num_cons1 = conta_consonanti(input1);
    int num_cons2 = conta_consonanti(input2);
    char *output = malloc(len1 + len2 + 1);
    if (output != NULL) {
        if (num_cons1 <= num_cons2) {
            copy_string(output, input1, 0);
            copy_string(output, input2, len1);
        } else {
            copy_string(output, input2);
            copy_string(output, input1, len1);
        }
        output[len1 + len2] = '\0';  // set the null terminator
    }
    return output;
}

int conta_consonanti(const char *vect) {
    int i, num_cons = 0;
    for (i = 0; vect[i] != '\0'; i++) {
        /* counting ASCII consonants, upper and lowercase */
        /* our French friends will miss the ç and our Spanish ones the ñ */
        if (strchr("BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz", vect[i])
            num_cons++;
    }
    return num_cons;
}

void copy_string(char *output, const char *input, int offset) {
    int i;
    for (i = 0; input[i] != '\0'; i++) {
        output[offset] = input[i];
        offset++;
    }
}
0 голосов
/ 30 января 2019

in

 concatena(input1, input2, output);
 printf("%s\n", output);

значение output не изменяется concatena , поэтому вы печатаете неинициализированный символ * => сбой или любое другое неопределенное поведение

вам нужно сделать вывод выходной переменной, поэтому void concatena(char *input1, char *input2, char **output) и т. Д. Вот так:

int main(void){
    char *input1, *input2, *output;
    input1 = "sdaeteruiop";
    input2 = "eiyearteoiana";
    concatena(input1, input2, &output);
    printf("%s\n", output);
    free(output);
    return 0;
}

void concatena(char *input1, char *input2, char **output){
    int num_cons1 = 0, num_cons2 = 0, dim_input1, dim_input2;
    conta_consonanti(input1, &num_cons1);
    conta_consonanti(input2, &num_cons2);
    if(num_cons1 < num_cons2){
        dim_input1 = strlen(input1) + strlen(input2);
        *output = malloc(dim_input1 + 1);
        strcpy(*output, input1);
        strcat(*output, input2);
    }else {
        dim_input2 = strlen(input2) + strlen(input1);
        *output = malloc(dim_input2 + 1);
        strcpy(*output, input2);
        strcat(*output, input1);
    }
}

Я также исправил ваш malloc, вы пропустили 1 символ для нулевого терминатора

предупреждение, если вывод num_cons2 == num_cons1 * не установлен, и вы по-прежнему печатаете его без инициализации, вам нужно установить его в NULL и проверить этот случай перед его печатью, или, более вероятно, заменить else if(num_cons2 < num_cons1) на else (вот чтоЯ делал это выше)

обратите внимание, что dim_input1 и dim_input2 имеют одинаковое значение, их бесполезно различать

, и первый вызов copy_string можно заменить на strcpy а второй - strcat, за исключением того, что copy_string пропущено, чтобы добавить окончательный нулевой символ .Я исключил использование copy_string

, предупреждающее, что объявление void concatena(char *, char *, char *); должно быть обновлено до void concatena(char *, char *, char **);

Выполнение:

eiyearteoianasdaeteruiop

Под valgrind:

pi@raspberrypi:~ $ valgrind ./a.out
==15629== Memcheck, a memory error detector
==15629== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==15629== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==15629== Command: ./a.out
==15629== 
eiyearteoianasdaeteruiop
==15629== 
==15629== HEAP SUMMARY:
==15629==     in use at exit: 0 bytes in 0 blocks
==15629==   total heap usage: 2 allocs, 2 frees, 1,049 bytes allocated
==15629== 
==15629== All heap blocks were freed -- no leaks are possible
==15629== 
==15629== For counts of detected and suppressed errors, rerun with: -v
==15629== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...