Разыменование указателя в инициализаторе цикла for вызывает ошибку сегментации

У меня проблема с использованием указателей в цикле for. В моем инициализаторе цикла for я разыменовываю указатель int и присваиваю ему значение "0". Когда я использую этот разыменованный указатель в цикле, я получаю ошибку сегментации, и я не понимаю, почему. Я использую Code :: Blocks и компилятор C GNU GCC.

  1. Глядя в окно наблюдения, я вижу, что во время цикла for переменная имеет случайное число.

  2. Похоже, что разыменованный указатель теряет область видимости во время цикла for.

Код:

#include <stdio.h>

int main(void)
{
    int val = 0;
    int *p = NULL;
    int answer = 0;

    p = &val;

    *p = 1; // This dereferences and sets to one successfully

    for (int i=3, (*p)=0 ; i>=0; i--) // Here *p is a random number
    {
        printf("do stuff");
        (*p) += 1; // Here it causes a segmentation fault
    }
    answer = *p;
}

Я думал, что не будет проблем с использованием указателя, как я.

Ответы

Ответ 1

Внимательно посмотрите здесь:

for (int i=3, (*p)=0 ; i>=0; i--)

В первой части for вы определяете новую переменную указателя с именем p, которая затеняет ранее определенный p, и инициализируете ее как NULL. Затем вы разыменовываете указатель NULL в цикле, который вызывает segfault.

Вы не можете иметь как определение переменной, так и присвоение существующей переменной вместе, вот так, поэтому переместите присвоение *p до цикла:

*p = 0;
for (int i=3; i>=0; i--)

Или вы можете определить i вне цикла:

int i;
for (i=3, (*p)=0 ; i>=0; i--)

Вы можете сжать их вместе, используя оператор запятой:

for (int i=(*p=0,3) ; i>=0; i--)

Здесь присваивание p происходит как часть инициализатора для i, поэтому оно не объявляет новую переменную. Но я не рекомендовал бы это, поскольку это сделало бы Ваш код более трудным для чтения и понимания.

Ответ 2

Вы объявляете совершенно новую переменную с именем p:

for (int i=3, (*p)=0 ; i>=0; i--)

Это так же, как:

for (int i=3, *p=0 ; i>=0; i--)

Итак, вы создаете int i и int *p, который указывает на адрес 0. Это не то же самое p, как определено ранее. Это просто затеняет его. Таким образом, когда вы разыменовываете это, вы получаете segfault.

Ответ 3

Совет: используйте -Wshadow, чтобы получить предупреждение, когда переменная затеняет другую.

[] $ gcc main.c -Wshadow
main.c: In function ‘main:
main.c:13:21: warning: declaration of ‘p shadows a previous local [-Wshadow]
   13 |     for (int i=3, (*p)=0 ; i>=0; i--) // Here *p is a random number
      |                     ^
main.c:6:10: note: shadowed declaration is here
    6 |     int *p = NULL;
      |          ^

https://coliru.stacked-crooked.com/a/5de37f53cf0b094d