Указатель-массив-внешний вопрос - PullRequest
20 голосов
/ 17 июня 2011

Файл 1.c

int a[10];

Файл main.c:

extern int *a;

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

Дает мне ошибку! Что не так?

Ответы [ 5 ]

24 голосов
/ 17 июня 2011

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

16 голосов
/ 17 июня 2011

Хорошо объяснено в C FAQ .И есть продолжение .Картинка во второй ссылке стоит миллион долларов.

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

enter image description here

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

2 голосов
/ 24 октября 2012

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

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

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

extern int myarray[];

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

0 голосов
/ 14 декабря 2016

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

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, вы получите ошибку сегмента, потому что у вас нет доступа к ox01.

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

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

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

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

0 голосов
/ 17 июня 2011

В основном вам нужно написать свой main.c так:

extern int a[];

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