глобальный указатель на массив - PullRequest
1 голос
/ 11 декабря 2011

Похоже, я до сих пор не получил правильные указатели на C.

Я хочу, чтобы длина глобального массива (указателя) j была динамической.

У меня есть этот (Arduino) код

unsigned int* j;

void setup() {

  Serial.begin(9600);

  initj();

  Serial.println(j[0]); //111 -> right
  Serial.println(j[0]); //768 -> wrong!
  Serial.println(j[1]); //32771 -> wrong!
}

void initj() {
  unsigned int i[2];
  i[0] = 111;
  i[1] = 222;

  j = i;

  Serial.println(j[0]); // 111 -> right
  Serial.println(j[1]); // 222 -> right
}

void loop() {
}

Как я могу сделать это правильно?

Заранее спасибо!

Ответы [ 3 ]

3 голосов
/ 11 декабря 2011

Ваша функция initj() устанавливает j для указания на локальный массив.Время жизни этого массива ограничено самим вызовом функции, как только функция возвращается, указатель больше не действителен.Поэтому попытка разыменования j означает неопределенное поведение .

Я не знаю точно, что вы хотите сделать, но есть три варианта:

  1. Вместо этого объявите i в глобальной области видимости.
  2. Объявите i как static.
  3. Динамически распределите массив, используя malloc (возможно, не подходит для встроенной платформы).
2 голосов
/ 11 декабря 2011

Это потому, что массив i[2] является локальным для функции initj(). Следовательно, когда функция возвращается, она больше не действительна. Таким образом, указатель j становится висящим указателем.

Итак, вы вызвали неопределенное поведение.

Что касается того, почему эти две строки ведут себя так, как они:

Serial.println(j[0]); //111 -> right
Serial.println(j[0]); //768 -> wrong!

Несмотря на то, что значения потеряны, они все еще находятся в стеке. Поэтому, когда вы обращаетесь к нему до вызова Serial.println, вы получаете «правильное» значение. Но этот вызов функции приводит к перезаписи стека. Таким образом, при втором вызове он дает неправильное значение.

Но в любом случае это все еще неопределенное поведение. Все может допускаться.


Чтобы исправить это, вам нужно поместить значения в область видимости функции setup(). Вы можете объявить i[2] глобально или в setup() и передать его в функцию initj().

Вы также можете динамически распределять массив в динамической памяти с помощью malloc(). (и обязательно освободите его позже с free())

1 голос
/ 11 декабря 2011

Как только initj сделан, его пространство стека уничтожается ОС (или фактически, указатель стека перемещается и адреса initj больше не являются надежными). Поскольку i существует в этом стековом пространстве, i исчезло. И вы просто скопировали значение i в j. Итак, в setup (), j - это висячий указатель.

...