Присвоение значения переменной сохраняется в неправильном месте? - PullRequest
2 голосов
/ 30 апреля 2010

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

#include <stdio.h>

int main()
{
    signed int tcodes[3][1];

    tcodes[0][0] = 0;
    tcodes[0][1] = 1000;
    tcodes[1][0] = 1000;
    tcodes[1][1] = 0;
    tcodes[2][0] = 0;
    tcodes[2][1] = 1000;
    tcodes[3][0] = 1000;
    tcodes[3][1] = 0;

    int x, y, c;

    for(c = 0; c <= 3; c++)
    {
        printf("%d %d %d\r\n", c, tcodes[c][0], tcodes[c][1]);

        x = 20;
        y = 30;
    }

}

Я ожидаю, что эта программа выведет:

0 0 1000
1 1000 0
2 0 1000
3 1000 0

Но вместо этого я получаю:

0 0 1000
1 1000 0
2 0 20
3 20 30

Это делается для любого номера, назначенного для x и y. По какой-то причине x и y переопределяют части массива в памяти.

Может кто-нибудь объяснить, что происходит?

Спасибо!

Ответы [ 6 ]

8 голосов
/ 30 апреля 2010

  tcodes[3][0] = 1000;   
  tcodes[3][1] = 0; 

дважды списывают конец вашего массива. [3] выделяет идентификаторы слотов 0-2, а [1] выделяет только 1 фактический интервал [0].

Измените инициализацию кодов на signed int tcodes[4][2]; для 4 записей по 2 записи.

5 голосов
/ 30 апреля 2010

Другие ответы верны, но чтобы помочь объяснить, что на самом деле происходит:

У вас есть следующие локальные объявления:

signed int tcodes[3][1];
int x, y, c;

Они сохраняются прямо рядом друг с другом в кадре стека в памяти:

tcodes
х
у
г

tcodes имеет 3 точки, и попытка записать в tcodes[n] просто означает найти, куда tcodes указывает в памяти, и перейти к n -ому месту (я собираюсь игнорировать ваше второе измерение так как все равно было всего 1). Если вы попытаетесь написать в точку 3, она переместится на 3 точки с начала tcodes, хотя tcodes не так уж велика. Поскольку x расположен сразу после tcodes, в месте, где будет tcodes[3], эта память перезаписывается и значение x изменяется. tcodes[4] будет перезаписывать y, а tcodes[5] будет перезаписывать z. Если вы продолжаете увеличивать n (или отрицательно, что законно), вы можете перезаписать в память все, что вам разрешено, что может испортить вашу программу плохими и труднодоступными способами

5 голосов
/ 30 апреля 2010

Измените это на:

signed int tcodes[4][2];
3 голосов
/ 30 апреля 2010

Если вы определите массив следующим образом:

int somearr[3];

Вы получаете массив, который имеет 3 элемента. Индексы начинаются с 0, поэтому эти элементы:

somearr[0]
somearr[1]
somearr[2]

Массивы и другие переменные, определенные внутри функции, как в вашем коде, размещаются в стеке. Так получилось, что переменные x и y помещаются в стек рядом с вашим массивом. Если вы пытаетесь получить доступ к элементам

tcodes[3][0] or tcodes[3][1]

Вы получаете доступ к части стека, которая находится за вашим массивом, и, как показывают ваши выходные данные, это место, где расположены переменные x и y.

На самом деле такое определение

signed int tcodes[3][1];

создает массив, содержащий 3 элемента, каждый из которых тоже является массивом - массивом, содержащим один со знаком int. Когда вы пишете tcodes [1] [1], вы получаете доступ к несуществующему «второму» элементу вашего второго массива. Место в памяти, к которому компилятор обращается при интерпретации tcodes [1] [1], перекрывается с tcodes [2] [0];

0 голосов
/ 01 мая 2010

Вам необходимо обратить внимание на решение, данное Робином Остером выше. Другие люди могут давать вам «слишком много информации». Просто лучше посчитайте количество элементов в каждом измерении, не забывайте, что количество нулевых элементов!

0 голосов
/ 30 апреля 2010

Когда вы пишете за пределами массива, вы пишете в памяти, выделенной для переменных x и y в стеке. В этом случае они совпадают с tcodes [3] [0] == x и tcodes [3] [1] == y, поскольку адреса совпадают. Если вы делаете это в вызываемой функции и массив передается по ссылке, это может привести к повреждению стека. Суть в том, что в C массивы основаны на 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...