Вопрос-массив-экстерн

20

Файл 1.c

int a[10];

Файл main.c:

extern int *a;

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

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

    
задан Rajendra Uppal 17.06.2011 в 14:39
источник

5 ответов

24

Массивы разлагаются или неявно преобразуются в указатели при передаче функции в качестве аргумента или при преобразовании в значение 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 были указателем на сам объект, а не на массив объектов.

    
ответ дан Jason 17.06.2011 в 15:27
источник
  • любые предложения о том, где я мог бы узнать больше об этом поведении? –  estebro 09.12.2016 в 22:55
  • Я смотрю на вывод компилятора, чтобы увидеть это поведение, это довольно очевидно, если вы знакомы с базовым языком ассемблера для своей платформы. Вы увидите, что ссылка на массив фактически обрабатывается машиной точно так же, как если бы это был доступ указателя. Этот вопрос здесь также может оказать некоторую помощь. –  Jason 20.12.2016 в 23:38
  • Спасибо за дополнительную информацию (и за возвращение к такому старому вопросу). –  estebro 21.12.2016 в 16:28
16

Хорошо объяснено в часто задаваемых вопросах C>. И есть продолжение . Изображение во втором звене стоит миллион долларов.

char a[] = "hello";
char *p = "world";

Короткий ответ: используйте extern int a[] .

    
ответ дан cnicutar 17.06.2011 в 14:40
источник
2

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

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

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

extern int myarray[];

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

    
ответ дан William Morris 24.10.2012 в 19:58
источник
0

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

extern int a[];

int main()
{
    printf("%d\n", a[0]);
    return 0;
}
    
ответ дан OzBandit 17.06.2011 в 14:46
источник
0

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

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, если вы хотите получить дополнительную информацию.

    
ответ дан abdullam 13.12.2016 в 22:13
источник