Члены массива перезаписаны последним элементом

StackOverflow https://stackoverflow.com/questions/895628

  •  23-08-2019
  •  | 
  •  

Вопрос

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

#include <stdio.h>

main()
{
    int i, cases;
    char num[1000000];

    scanf("%d", &cases);
    char* array[cases];

    //store inputs in array
    for(i=0; i<cases; i++)
    {
        scanf("%s", &num);
        array[i] = &num;
    }

    //print out array items and their memory addresses
    for(i=0; i<cases; i++)
    {
        printf("%d %s\n", i, array[i]);  //print (array index) (array value) 
        printf("%d %p\n", i, &array[i]); //print (array index) (array address) 
    }
}

Inputs:
3 <-- number of lines to follow
0   <-- put in array[0]
1   <-- put in array[1]
2   <-- put in array[2]

Outputs
0 3         <-- why is this being overwritten with the last element?
0 0013BCD0
1 3         <-- why is this being overwritten with the last element?
1 0013BCD4
2 3
2 0013BCD8

Нет правильного решения

Другие советы

Результатом здесь является линия array[i] = &num; вы устанавливаете значение array[i] элемент по адресу num множество;с array это массив символов, я подозреваю, что он усекает ваш num адрес массива, а младший байт просто равен 3.

Однако.Тем не менее, ваш char num[1000000] имеет ужасную форму, и вам вообще не следует этого делать.Выделите в кучу и выберите меньшее число, ради всего святого.Кроме того, scanf("%s", &num) на самом деле не даст вам того, что вы хотите.Вот подсказка;используйте цикл getc() для чтения чисел;это позволяет избежать необходимости выполнять предварительное выделение массива для scanf().

Это потому, что вы помещаете в каждый индекс массива один и тот же адрес (адрес char num[1000000];).

Это ошибка, которая приведет к динамическому выделению (calloc, malloc, new и т. д.).

Ваше здоровье!

Внутри вашего первого цикла вы должны (но вы этого не делаете) записывать каждый ввод в отдельный элемент массива num;вместо этого вы всегда пишете в одно и то же место, т.е.к &num.

char* массив[случаи];

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

Заменять

//store inputs in array
for(i=0; i<cases; i++)
{
    scanf("%s", &num);
    array[i] = &num;
}

с

array[0] = num;
//store inputs in array
for(i=0; i<cases; i++)
{
    scanf("%s", array[i]);
    array[i+1] = array[i] + strlen(array[i]) + 1;
}

сканировать каждую строку в первое доступное место в num[], и установите следующий элемент array[] чтобы указать на следующее доступное место.Теперь ваш printf() струн будет работать.Оригинал сканировал каждую строку в начало num[].

Примечание: scanf() с неукрашенным %s так же плохо, как gets(), потому что он не накладывает ограничений на объем передаваемых данных.Не используйте его в реальном коде.

Заменять

    printf("%d %p\n", i, &array[i]); //print (array index) (array address) 

с

    printf("%d %p\n", i, (void*)(array[i])); //print (array index) (array address) 

чтобы на самом деле распечатать адреса, хранящиеся в a[], а не адреса элементов a[].Актерский состав необходим, потому что %p ожидает указатель наvoid поэтому вы должны предоставить его.

Это ваш исправленный код:

#include <stdio.h>

main(void)
{
    int i, cases;

    scanf("%d", &cases);
    char* array[cases];

    //store inputs in array
    for(i=0; i<cases; i++)
    {
        char *num = malloc(100000);
        scanf("%s", num);
        array[i] = num;
    }

    //print out array items and their memory addresses
    for(i=0; i<cases; i++)
    {
        printf("%d %s\n", i, array[i]);  //print (array index) (array value)
        printf("%d %p\n", i, (void*)&array[i]); //print (array index) (array address)
    }
    return 1;
}

Вы также можете использовать

char *num = calloc(100000, sizeof(char));

что немного оборонительно.Я не знаю, зачем вам 100 000.Вы можете сделать это динамически, используя malloc.Это потребует больше работы, но очень надежно.

В вашем коде происходит то, что вы сохраняете строку %s по адресу num, который не меняется, а затем присваиваете элемент array[i] этому адресу.Присваивание в C — это не что иное, как сохранение ссылки, вы не сохраняете сам элемент — это была бы пустая трата места.Итак, поскольку все элементы массива указывают на адрес (сохраняют только ссылку), значение в адресе меняется, а значит, и ссылка, поэтому все они меняются на 2 (а не на 3, как вы указали в своем сообщении).

Кажется, именно для таких вещей и создан C++.Анализ пользовательского ввода и динамическое распределение выполняются более безопасно и быстро.Я не могу представить себе систему с таким пользовательским интерфейсом, в которой нельзя было бы переключиться на C++.

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


В вашем коде есть несколько распространенных ошибок для новичков в C и вещей, которые в настоящее время не следует делать таким образом.

Если я правильно понимаю, вы хотите сохранить несколько строк ввода пользователя (вывод вашего примера немного вводит в заблуждение, поскольку вы показываете только цифры).

Вы готовите массив для хранения всех указателей (количество регистров) на строки, но резервируете память только для одной строки.Вам нужно сделать это для каждой строки, поэтому случаев.Для простоты урока «динамическое распределение памяти» я рекомендую сделать это следующим образом: char* array[cases][10000]; Это дает вам строки из 10 тысяч символов.

Вероятно, вы также не захотите иметь отдельные указатели на элементы вашего массива.Это начинает иметь смысл, если вы хотите отсортировать элементы массива, когда эти элементы больше, чем сами указатели.В этом случае ваш выигрыш в производительности заключается не в перемещении (копировании) больших фрагментов, а только в указателях (обычно 4 байта).В вашем случае длина int также составляет 4 байта.А ты все равно не сортируешь :)

scanf() это, мягко говоря, опасно.Во втором приложении вы даете ему указание записать строку по адресу массива.Кажется, это простая ошибка, но она может привести ко многим проблемам.Вероятно, вы захотите сделать это следующим образом: scanf("%d", &array[i]); (К сожалению, у меня под рукой нет компилятора, поэтому я не уверен на 100%).скиньте следующую строчку :)


Вопрос к специалистам по Markdown:Почему чертовски невозможно объединить LISTS с CODE-блоками?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top