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

17

Файл 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 ответов

23

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

Хорошо объяснено в часто задаваемых вопросах 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
источник