Нарушение доступа к памяти в C

Я создал программу периодической таблицы на C с динамическим полем, или, по крайней мере, я пытался.

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

Компилятор ничего не говорит, но я получаю ошибку времени выполнения: «нарушение доступа к памяти»

Что я упустил/упустил?

Вывод должен отображать только сохраненные элементы (алюминий/радий).

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


  typedef struct
  {
    char Name[20];
    char Symbol[3];
    char Atomicnumber[5];
    char* entrys;
  } Element;


int main(void)
{
    //Define the two entrys/elements

    Element Aluminium;
    strcpy(Aluminium.Name, "Aluminium");
    strcpy(Aluminium.Symbol, "Al");
    strcpy(Aluminium.Atomicnumber, "13");

    Element Radium;
    strcpy(Radium.Name, "Radium");
    strcpy(Radium.Symbol, "Ra");
    strcpy(Radium.Atomicnumber, "88");

    int size=0;
    //Define field
    printf ("size of field:");
    scanf( "%d" , &size);
    //Gives the saved Elements an Adress in Array/Field  

    Element Periodictable [size];

    strcpy(Periodictable[13].Name, "Aluminium");
    strcpy(Periodictable[13].Symbol, "Al");
    strcpy(Periodictable[13].Atomicnumber, "13");
    strcpy(Periodictable[13].entrys, "1");

    strcpy(Periodictable[88].Name, "Radium");
    strcpy(Periodictable[88].Symbol, "Ra");
    strcpy(Periodictable[88].Atomicnumber, "88");
    strcpy(Periodictable[88].entrys, "1");

    void output(Element* Periodictable, int*entry);

    printf("Recorded elements:\n");
    printf("\n");
    for (int i=1; i<= size; i++)
    {
        if (Periodictable[i].entrys)
        {
            printf("Name: %s \n",Periodictable[i].Name);
            printf("Symbol: %s \n",Periodictable[i].Symbol);
            printf("Atomic number: %s \n",Periodictable[i].Atomicnumber);
            printf("\n");
        }
        else i++;
    }

    return (0);
}

вывод должен быть таким:

Recorded elements:
Name: Aluminium
Symbol: Al
Atomic number: 13
Name: Radium
Symbol: Ra
Atomic number: 88

Определенное поле все еще должно быть создано, но пустые поля/адреса не должны отображаться в консоли.


person Roflcopter147    schedule 05.02.2017    source источник
comment
если размер ‹ 89 то у вас будут проблемы. Что вы вводите в качестве размера?   -  person Jean-François Fabre    schedule 06.02.2017
comment
entrys — это указатель на символ без выделенной для него памяти. Поэтому эта строка strcpy(Periodictable[13].entrys, "1"); завершится ошибкой   -  person Ed Heal    schedule 06.02.2017
comment
в качестве примечания: я настоятельно рекомендую вам создать файл конфигурации, который вы будете читать, вместо того, чтобы копировать/вставлять весь код для создания 116 элементов.   -  person Jean-François Fabre    schedule 06.02.2017
comment
@Jean-FrançoisFabre - Сейчас 118 элементов   -  person Ed Heal    schedule 06.02.2017
comment
@EdHeal, как я мог забыть об этом ;) если вам нужен мой вклад, кофе должен быть полноценным элементом.   -  person Jean-François Fabre    schedule 06.02.2017
comment
@ Жан-Франсуа Фабр макс. 118. Но до того, как я получил последнее сообщение об ошибке, во время программирования размер переменной не был проблемой, или, по крайней мере, компиляция не показала ничего неправильного.   -  person Roflcopter147    schedule 06.02.2017
comment
К вашему сведению, это ошибка времени выполнения, а не ошибка времени компиляции.   -  person OldProgrammer    schedule 06.02.2017
comment
char* entrys; предназначен для указателя на строку, а не на память для строки. Вы хотите char entrys[4]; вместо этого?   -  person Richard Chambers    schedule 06.02.2017
comment
@Richard Chambers изменился, но все та же ошибка   -  person Roflcopter147    schedule 06.02.2017
comment
@EdHeal, он должен иметь что-то против Ununseptium и Ununoctium...   -  person David C. Rankin    schedule 06.02.2017
comment
Индекс для изучения массива из [size] элементов в C должен быть от 0 до (размер-1). Цикл for for(int i=1; i<= size; i++) должен быть for(int i=0; i< size; i++). А в другом случае else i++; скроет следующий элемент.   -  person J. Piquard    schedule 06.02.2017
comment
Два изменения. Сделайте Element Periodictable [size]; равным Element Periodictable [size] = {0};, чтобы инициализировать его всеми нулями. Измените свой тест в цикле с if (Periodictable[i].entrys) на if (Periodictable[i].entrys[0]). Также исправьте управление внешним видом с for (int i = 1; i <= size; i++) на for (int i = 0; i < size; i++). Я предполагаю, что ваш компилятор C допускает динамическое выделение массива с помощью массива Periodictable.   -  person Richard Chambers    schedule 06.02.2017
comment
:43:5: ошибка: объект переменного размера не может быть инициализирован Element Periodictable [size] ={0};   -  person Roflcopter147    schedule 06.02.2017


Ответы (1)


Есть несколько проблем с вашим кодом.

  1. Член entrys является указателем на char, который никогда не инициализируется и не получает динамически выделяемую память. Вы объявили остальные 3 члена статически и инициализировали их значения с помощью strcpy. Однако strcpy не следует использовать для нераспределенных указателей, так как вы можете записывать в произвольное пространство памяти за пределами памяти, выделенной для запуска вашей программы. Нарушение доступа к памяти #1.

  2. Вы выделяете Periodictable на основе пользовательского ввода. Итак, если пользователь вводит число меньше 89, вы пытаетесь получить доступ к другому пространству памяти, которое может быть за пределами вашей программы, когда вы ссылаетесь на Periodictable[88]. Поскольку вы знаете количество элементов с самого начала, вы можете использовать простой фиксированный массив, который будет содержать все 118 элементов (таким образом, размер 119, если вы хотите сохранить индекс массива по номеру элемента и игнорировать элемент 0). Нарушение доступа к памяти #2.

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

  4. if (Periodictable[i].entrys) не будет работать, поскольку вы не разыменовываете указатель entrys из исходной реализации. Если вы решили оставить entrys в качестве указателя, вместо этого вы можете написать if (*Periodictable[i].entrys). Однако кажется, что нет необходимости использовать указатель, вместо этого можно было бы использовать простой char (на самом деле bool был бы даже более подходящим и разборчивым).

  5. Вы обязательно пропускаете элемент с оператором else i++, он просто еще не отображался, потому что в массиве зарегистрировано недостаточно элементов. Вам не нужно снова увеличивать i, поскольку цикл for уже делает это.

  6. В вашем коде есть два стиля инициализации, и оба они могут работать. Один — записывать значения непосредственно в массив, другой — объявлять элементы в стеке, записывать в них и копировать в массив. В приведенном ниже коде два элемента инициализируются по-разному в качестве примера.

Итак, вот как будет выглядеть код.

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

#define MAXSIZE 119

typedef struct
  {
    char Name[20];
    char Symbol[3];
    char Atomicnumber[5];
    char entrys;
  } Element;


int main(void)
{
    Element Periodictable [MAXSIZE];
    memset(&Periodictable, 0, sizeof(Element) * MAXSIZE);

    Element Aluminium;
    strcpy(Aluminium.Name, "Aluminium");
    strcpy(Aluminium.Symbol, "Al");
    strcpy(Aluminium.Atomicnumber, "13");
    Aluminium.entrys = 1;
    memcpy(&Periodictable[13], &Aluminium, sizeof(Element));

    strcpy(Periodictable[88].Name, "Radium");
    strcpy(Periodictable[88].Symbol, "Ra");
    strcpy(Periodictable[88].Atomicnumber, "88");
    Periodictable[88].entrys = 1;

    printf("Recorded elements:\n");
    printf("\n");
    for (int i=1; i<= MAXSIZE; i++)
    {
        if (Periodictable[i].entrys)
        {
            printf("Name: %s \n",Periodictable[i].Name);
            printf("Symbol: %s \n",Periodictable[i].Symbol);
            printf("Atomic number: %s \n",Periodictable[i].Atomicnumber);
            printf("\n");
        }
    }

    return (0);
}

И выводит:

Recorded elements:

Name: Aluminium
Symbol: Al
Atomic number: 13

Name: Radium
Symbol: Ra
Atomic number: 88

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

person Thiago Turchetti Maia    schedule 25.04.2019