C ошибка выделения памяти. Не найти что-то подобное - PullRequest
0 голосов
/ 03 мая 2020

Не могли бы вы помочь, пожалуйста? Когда я выполняю этот код, я получаю следующее: AAAAABBBBBCCCCCBBBBBCOMP¬ıd┐╔ LENGTH 31 После букв есть несколько странных символов, а я выделил всего 21 байт.

#include <stdio.h>
#include <stdlib.h>
char * lineDown(){
    unsigned short state[4] = {0,1,2,1};
    char decorationUp[3][5] = {
        {"AAAAA"},{"BBBBB"},{"CCCCC"}
    };
    char * deco = malloc(21);
    int k;
    int p = 0;
    for(int j = 0; j < 4; j++){
        k = state[j];
        for(int i = 0; i < 5; i++){
           *(deco+p) = decorationUp[k][i];
           p++;
        }
    }
    return deco;
}
int main(void){

    char * lineDOWN = lineDown();
    int k = 0;
    char c;
    do{
        c = *(lineDOWN+k);
        printf("%c",*(lineDOWN+k));
        k++;
    }while(c != '\0');
    printf("LENGTH %d\n\n",k);
}

Ответы [ 2 ]

1 голос
/ 03 мая 2020

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

char * deco = malloc(21);

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

    //... 
    *(deco + p ) = '\0';

    return deco;
}

В противном случае это do-while l oop

do{
    c = *(lineDOWN+k);
    printf("%c",*(lineDOWN+k));
    k++;
}while(c != '\0')

будет иметь неопределенное поведение.

Но даже если вы будете добавьте массив с завершающим нулем, l oop будет неверно считать длину сохраненной строки, потому что это увеличит переменную k, даже если текущий символ является конечным нулем.

Вместо этого вы должны использовать некоторое время l oop. В этом случае объявление переменной c будет избыточным. L oop может выглядеть как

while ( *( lineDOWN + k ) )
{
    printf("%c",*(lineDOWN+k));
    k++;
}

В этом случае этот вызов

printf("\nLENGTH %d\n\n",k);
        ^^

выведет правильную длину строки, равную 20.

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

Учтите, что ваша программа полна магических чисел c. Такая программа обычно подвержена ошибкам. Вместо этого вы должны использовать именованные константы.

0 голосов
/ 03 мая 2020

В

char decorationUp[3][5] = {
    {"AAAAA"},{"BBBBB"},{"CCCCC"}
};

вашей строке требуется 6 символов, чтобы также разместить нулевой символ, даже в этом случае вы не используете их как «стандартную» строку, а только массив символов. Чтобы войти в привычку, всегда поменяйте местами конечный нулевой символ

, вы можете сделать

char decorationUp[3][6] = {
    {"AAAAA"},{"BBBBB"},{"CCCCC"}
};

Обратите внимание, что указывать первый размер бесполезно, компилятор считает вас

Поскольку в main вы останавливаетесь, когда читаете нулевой символ, вам также необходимо поместить его в deco в конце, поэтому вам нужно выделить 21 для него. Как и прежде, вы пропустили место для нулевого символа, но здесь это приводит к неопределенному поведению, потому что вы читаете после выделенного блока.

Чтобы сделать *(deco+p) не читаемым, выполните deco[p]

Так, например:

char * lineDown(){
    unsigned short state[] = {0,1,2,1};
    char decorationUp[][6] = {
        {"AAAAA"},{"BBBBB"},{"CCCCC"}
    };
    char * deco = malloc(4*5 + 1); /* a formula to explain why 21 is better than 21 directly */
    int k;
    int p = 0;
    for(int j = 0; j < 4; j++){
        k = state[j];
        for(int i = 0; i < 5; i++){
           deco[p] = decorationUp[k][i];
           p++;
        }
    }
    deco[p] = 0;
    return deco;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...