Необъявленный массив заселяемых структур - PullRequest
0 голосов
/ 12 марта 2012

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

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
int score;
}player;

void printScore(player *p, int num);

int main(void)
{

    printf ("\nEnter number of players (1 - 4)\n");
    scanf ("%d", &numPlayers);

    player *p = (player*)malloc(sizeof(player) * 3);

    for (i=0;i<numPlayers;i++)
    {
        printScore(p, i);
    }

}

void printScore(player *p, int num)
{

        p[num].score = 1;
        printf ("%d\n", p[num].score);
}

3 в функции malloc на самом деле должны быть numPlayers.Если я оставлю это в 3, и введу большее число в меню, программа обычно вылетает, но иногда она работает.Как это возможно?Если у меня достаточно памяти только для p [0], p [1], p [2], как (например) p [15] .score вообще существует для заполнения?

Ответы [ 4 ]

1 голос
/ 12 марта 2012

Это называется "неопределенное поведение".Когда поведение не определено - все возможно.Доступ к неверному указателю (как в вашем примере) является одним из многих случаев, когда поведение программы не определено стандартом, и компилятор может делать все, что пожелает.

Любое поведение в этом случае является правильным.В вашем случае компилятор просто ничего не делает, и программа запускает , как если бы выделяла память.Если ОС не убивает вас за это (= программа падает при нарушении прав доступа) - это ваша чистая удача.

0 голосов
/ 12 марта 2012

Карта программ в памяти может быть организована, например: (текст + данные + bss)

Эта карта создается во время компиляции и остается постоянной во время выполнения, ваша программа может расширяться в незанятую часть виртуальной памяти во время выполнения при использовании динамического выделения памяти malloc ().

Ваша программа: 1- Во время выполнения он выделяет 3 сегмента памяти в памяти (HEAP).

2- p инициализируется функцией malloc с адресом NNNN в куче. Это местоположение первого набора из 3 выделенных сегментов. Первый адрес (p + 0 * (sizeof (игрок))), второй набор будет в (p + 1 * (sizeof (игрок))) и третий адрес в (p + 2 * (sizeof (игрок))).

С C вы можете попытаться получить доступ куда угодно, но вам нужно установить механизмы безопасности, чтобы не повредить ваш код, ваши данные или некоторую незащищенную зону. Пример механизма безопасности в этом случае: используйте numPlayers * sizeof вместо константы «3» в 3 * sizeof или проверьте ввод пользователя.

Таким образом, любой доступ на чтение / запись к p [15] будет направлен на (p + 15 * (sizeof (player))).

3- Почему он заселен? Память может содержать другие данные из вашей программы или просто шум. Вот что заполняет ваши поля структуры.

4- Почему это случайный сбой? Ваш доступ на запись приведет к повреждению данных, но это может быть не достаточно плохо для сбоя. Если вы войдете в память в направлении сегмента ТЕКСТ. Вы испортите свой код и обязательно потерпите крах.

0 голосов
/ 12 марта 2012

В С резервирование памяти это именно то, что резервирование .Он не накладывает ограничения на то, что фактически выделяется, он только гарантирует, что запрошенное вами пространство было зарезервировано для вашего использования.Ваша программа начинает читать то, что по праву принадлежит вам, а затем продолжает читать содержимое памяти, к которой у вас нет прав доступа.Менеджер памяти, скорее всего, позволит вам продолжать читать память.С не защищает вас от этого.Вам решать, что вы выделили и что вам разрешено читать.

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

0 голосов
/ 12 марта 2012

В коде C вы должны помнить, что вы управляете реальной памятью, компилятор не поможет вам проверить недопустимый доступ к памяти.

p - указатель на кучу, p имеет длину 3 * sizeof (player), но после этого память все еще может существовать, но значение непредсказуемо.

...