Подтвердить что ты не робот

Вопрос-указатель-экстерьер

Файл 1.c

int a[10];

Файл main.c:

extern int *a;

int main()
{
    printf("%d\n", a[0]);
    return 0;
}

Дает мне segfault! Что не так?

4b9b3361

Ответ 1

Массивы разлагаются или неявно преобразуются в указатели при передаче функции в качестве аргумента или при преобразовании в значение r в правой части оператора присваивания. Так что-то вроде:

int array[10];
int* a = array;  //implicit conversion to pointer to type int

void function(int* a);
function(array);  //implicit conversion to pointer to type int

работает просто отлично. Но не означает, что массивы сами по себе являются указателями. Поэтому, если вы обрабатываете массив, как указатель, как вы это делали, вы фактически рассматриваете тип массива как-бы если он был указателем, который содержал адрес для объекта int. Поскольку ваш массив на самом деле представляет собой последовательность объектов int, а не указывает на объекты int, вы фактически пытаетесь разыменовать какое-то место в памяти, которое не указывает ни на что иное (т.е. Первый слот в array представляет собой числовое целочисленное значение, подобное 0, которое будет похоже на разыменование NULL). Вот почему вы преуспеваете. Обратите внимание, что если вы сделали что-то вроде этого:

int array[] = { 1, 2, 3, 4, 5};
int b = *array;

Это все еще работает, поскольку array снова неявно преобразуется в указатель на блок памяти, который удерживает последовательность целых значений и затем разыменовывается, чтобы получить значение в первой последовательности. Но в вашем случае, объявив ваш массив текущему модулю кода как внешне определенному указателю, а не массиву, он пропустит неявное преобразование в указатель, который обычно выполняется, и просто используйте объект массива as-if были указателем на сам объект, а не на массив объектов.

Ответ 3

Немного позднее, дубликат этой проблемы был только что введен (и закрыт). В ответах здесь не упоминаются файлы заголовков...

Проблема будет поймана во время компиляции, если вы поместите объявление массива a в заголовочный файл, где он принадлежит, вместо того, чтобы помещать его в файл .c. Затем заголовочный файл должен быть включен в оба файла .c, и компилятор может видеть, что то, что вы заявили, неверно.

Ваш заголовочный файл будет содержать:

extern int myarray[];

Вы получите что-то вроде "error: conflicting types for a", если вместо этого укажете a как указатель.

Ответ 4

В основном вам нужно написать свой main.c следующим образом:

extern int a[];

int main()
{
    printf("%d\n", a[0]);
    return 0;
}

Ответ 5

Проверьте вывод следующего кода.

file1.c

#include <stdio.h>

extern int* my_arr;

void my_print()
{
  printf("%d", my_arr);
}

main.c

#include <stdio.h>

int my_arr[2] = {1,2};

extern void my_print();

void main()
{
    my_print();
}

Выход

1

внутри File1.c my_arr - это указательная переменная, которая имеет значение 1. означает, что ему был присвоен 1-й элемент my_arr []. Затем, если вы используете * my_arr для доступа к ячейке памяти ox1, вы получаете ошибку seg, потому что вам не разрешено обращаться к ox01.

Почему указатель my_arr был назначен 1 (первый элемент my_arr [])?

Имеет отношение к тому, как работает ассемблер. Прочитайте в этой статье

Почему ваш код не может получить доступ к 0x01?

Я знаю, что это связано с операционной системой, не позволяющей доступу к адресному пространству по коду пользователя. Это все, что я знаю. google, если вы хотите получить дополнительную информацию.