C может кто-нибудь сказать мне, что здесь происходит? - PullRequest
0 голосов
/ 06 октября 2009

Я не могу понять, какого чёрта здесь происходит. Я ожидаю, что в выводе должно быть сказано, что в ключах есть только 1 элемент, то есть 7, когда я выделил только позицию 0 с 120 байтами.

void add2(char **b, char *i) {
    if (!i) {
        b[0] = (char*) malloc(120);
        sprintf(b[0], "%s", "hithere");
    } else {
        strcat(b[0], "\\\\");
        strcat(b[0], i);
    }
}

void add1(char **b) {
    add2(b, NULL);
    add2(b, "one");
    add2(b, "two");
    add2(b, "three");
}

void add() {
    char *keys[2];
    int i;
    add1(keys);
    fprintf(stderr, "%s\n", keys[0]);
    for (i = 0; keys[i]; i++)
        fprintf(stderr, "%d\n", i);
    free(keys[0]);
}

int main (int argc, char** argv)
{   
     add();
     add();
     return 255;
}

выходы: hithere \ один \ два \ три 0 1 2 3 4 5 6 7 hithere \ один \ два \ три 0 1 2 3 4 5 6 7

строки такие, как я и ожидал, однако я думал, что только 0 должно быть распечатано, так как 0 - единственный элемент, к которому я добавил. Мне нужно иметь возможность освобождать каждое пятно вместо просто free [0], но когда я помещаю free [i] в ​​цикл for, который выводит его, он складывает дампы.

в отношении инициализации из ответа ниже, если мне нужен массив, подобный 1000 вместо 2, то как мне инициализировать их все в 0 без ввода 1000 0

Ответы [ 4 ]

4 голосов
/ 06 октября 2009
/* ... */
void add() {
    char *keys[2];
/* ... */

keys - это массив из двух указателей на char, но не инициализируется .
Попробуйте это

/* ... */
void add() {
    char *keys[2] = {0, 0}; /* explicit initialization of the two elements */
/* ... */

В отсутствие явных инициализаторов для всех членов, неинициализированные из них инициализируются в ноль (правый ноль для их типа).

/* ... */
void add() {
    char *keys[1000] = {42}; /* explicit initialize the first element to 42 */
                             /* and implicitly initialize all other elements to 0 */
                             /* **ATTENTION** */
                             /* initializing a pointer to 42 is wrong */
                             /* I only wrote that as an example */
/* ... */

Редактировать , цитата из стандарта

6.7.8 Инициализация
Синтаксис
1

инициализатор:

назначение выражение
{initializer-list}
{initializer-list,}

список инициализаторов:

обозначение opt инициализатор
инициализатор-список, обозначение opt инициализатор

Нет синтаксиса для пустого списка инициализаторов.

3 голосов
/ 06 октября 2009

Вы не инициализировали массив ключей, поэтому он содержит все, что случилось в памяти. ключи [1] и до 7 не были равны нулю в этом случае.

1 голос
/ 06 октября 2009

В чем разница между неявная инициализация элементов массива в 0 и явно установить их в 0 с memset ()?

char *data[1000] = {0};
memset(data, 0, sizeof data);

Первая опция (неявная инициализация) устанавливает каждый элемент массива в ноль соответствующего типа; вторая опция устанавливает все биты всех элементов (плюс любое заполнение) на 0. Обычно ( 99,99% всех текущих компьютеров ) нет разницы между , набранными 0 и все биты 0 .

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

void *test = 0; /* can make test something like "0xC0DE:0x0000" */
memset(test, 0, sizeof test); /* will make test as "0x0000:0x0000" */
1 голос
/ 06 октября 2009

Для второй части вопроса,

Если вам нужно инициализировать массив, например, 1000 вместо 2, используйте следующее

char *keys[1000] = {0};

Если вы инициализируете один элемент массива значением, то все остальные члены массива будут автоматически инициализированы нулем.

т.е. если вы используете

char *keys[1000] = {42};

тогда первый член массива будет инициализирован равным 42, а все остальные члены массива будут автоматически инициализированы нулем.

...