Указатель на массив, совместно используемый несколькими исходными файлами

Это мой файл1 с именем main.c

#include <stdio.h>
#include <stdlib.h>

#define MONTHS 12
void ChangeDay(void);
int* days;

int main(void)
{
    days = (int*) malloc(MONTHS * sizeof(int));
    if(days != NULL)    
        ChangeDay();    
    else    
        return 1;   
    printf("%2d.\n", days[0]);
    return 0;
}

Глобальная переменная days объявлена ​​как указатель на тип int, а malloc используется для выделения места для 12 целых чисел.

Это мой файл 2 под названием day.c

int days[];
void ChangeDay(void)
{
    days[0] = 31;
}

При вызове функции ChangeDay первому элементу массива days присваивается десятичное значение 31.

Это вывод кода:

root @ where: ~ gcc -m32 -Wall -o day main.c day.c
day.c: 1: предупреждение: предполагается, что массив 'days' содержит один элемент
root @ where: ~. / day Ошибка сегментации

Буду признателен, если вы объясните мне эти результаты.

Мои вопросы :

  • Как правильно объявлять переменные (включая массивы) в нескольких исходных файлах?
  • Как получить доступ к элементу массива с помощью указателя, если они объявлены в разных файлах?

person boleto    schedule 24.07.2013    source источник
comment
в day.c вы должны добавить extern   -  person Grijesh Chauhan    schedule 24.07.2013
comment
Сбой, который вы видите, является следствием нарушения одного правила определения C, что приводит к неопределенному поведению.   -  person jxh    schedule 24.07.2013
comment
Не используйте результат malloc.   -  person chris    schedule 24.07.2013


Ответы (3)


Каждое объявление идентификатора объекта должно иметь тип, совместимый с другими объявлениями. int *days и int days[] - разные типы. Первый - это указатель на int. Последний представляет собой массив int.

В первом файле используйте:

int *days;

Во втором файле используйте:

extern int *days;

Дополнительно: int *days; - это предварительное определение для days. Когда компилятор достигает конца единицы трансляции (компилируемого исходного файла), он изменяет предварительное определение на определение объекта (с нулевым инициализатором). extern int *days; - это объявление days, которое не является определением. Он сообщает компилятору, что days - это имя объекта, который существует где-то еще.

У вас должно быть только одно определение для каждого объекта. Другие файлы, которые ссылаются на объект, должны только объявлять имя, а не определять объект.

Иногда возникает путаница с объявлением, например int days[], потому что использование этого параметра в параметре функции объявляет, что параметр имеет тип int *. Это специальная настройка, которая происходит только в параметрах функции, а не в других объявлениях.

person Eric Postpischil    schedule 24.07.2013
comment
Эрик, но это не сегментация - я думаю, причина неисправности! - person Grijesh Chauhan; 24.07.2013
comment
@GrijeshChauhan: Я тестировал исходный код и свой код. Мое изменение устраняет проблему. - person Eric Postpischil; 24.07.2013
comment
потому что это правильное исправление, даже я собирался ответить на это, но проверьте свой ответ, я тоже дал ссылку на кодовую карту. - person Grijesh Chauhan; 24.07.2013
comment
Я просто хотел поделиться с вами: неудивительно, что этот код выполняется, тогда как если вы используете правильные флаги, как я предлагал, вы получите ошибку времени компиляции !! Точно так же я удивляюсь, почему код OP может компилироваться - возможно, это ошибка в компиляторе. - person Grijesh Chauhan; 24.07.2013
comment
@GrijeshChauhan: Я скомпилировал, как обычно, с флагами GCC «-Wmost -pedantic -std = c99». Здесь нет ошибки компиляции. Можете ли вы процитировать раздел стандарта C, который якобы нарушается? - person Eric Postpischil; 24.07.2013
comment
на самом деле мое обсуждение с вашим - это мое замешательство. Я написал этот код случайно, когда писал здесь ответ. У меня не было ссылки, чтобы прочитать об этом, но я проверил, что если я компилирую свой код без -pedantic -error, он компилируется и выполняется, а если я использую флаг, это ошибка! Это было / и это перестало удивлять меня! - person Grijesh Chauhan; 25.07.2013
comment
Кстати, ваш ответ хорош, и спасибо за руководство и помощь! Если вы найдете что-то связанное с этим, дайте мне знать. - person Grijesh Chauhan; 25.07.2013

Причина ошибки сегментации:

int days[]; // is errror 
void ChangeDay(void)
{
    days[0] = 31;
}

объявление это ошибка int days[];, вы не указываете ей размер и не инициализируете ее. Таким образом, вы не можете использовать day[0] = 31; - это незаконно и вызывает ошибку сегментации.

Чтобы получить сообщение об ошибке вместо предупреждения, скомпилируйте свой код, например:

gcc -pedantic -error только тогда выдаст ошибку.

иначе этот код не выдаст вам ошибки. Это сбивает с толку, но проверьте, работает ли этот код Codepade. и этот код выдаст вам ошибку, если вы скомпилируете правильные флаги, как я предлагал.

Кроме того, если вы хотите поделиться тем же массивом day[], объявите его, как предлагает @Eric Postpischil

В настоящее время я не удаляю свой ответ, так как хочу, чтобы другие пользователи просматривали связанный код @ codepade и сообщали мне, следует ли его компилировать с новыми компиляторами? или это ошибка в компиляторе?

person Grijesh Chauhan    schedule 24.07.2013
comment
Объявление int days[]; само по себе не является проблемой. Он объявляет days с неполным типом. Вы можете определить days в одном файле с помощью int days[3];, например, и объявить его в другом файле с помощью extern int days[];. Однако, поскольку вопрос показывает, что days назначается память с malloc, либо это должен быть указатель, а не массив, либо это должен быть массив, а malloc следует удалить. - person Eric Postpischil; 24.07.2013
comment
@EricPostpischil Нет int days[]; правильно в качестве аргумента функции, но в качестве формального объявления ее ошибки в соответствии со стандартом C. - person Grijesh Chauhan; 24.07.2013
comment
Извините, я не понимаю эту фразу. Вы хотите сказать, что такое заявление, как void foo(int days[]);, незаконно? Это законно. Он настроен на void foo(int *days); согласно C 2011 (N1570) 6.7.6.3 7. Если вы говорите, что это незаконно в области файлов, это также неверно; int days[]; - это юридическая декларация. - person Eric Postpischil; 24.07.2013
comment
@EricPostpischil ok Какой компилятор у вас есть, попробуйте код, который я связал, или код OP с предложенным мной флагом или без него. - person Grijesh Chauhan; 24.07.2013
comment
@EricPostpischil Нет void foo(int days[]); является действительным, но какое объявление OP, данное в его коде, и то, что я дал в своем связанном коде, неверно. Он мог скомпилироваться, потому что его компилятор глючил. - person Grijesh Chauhan; 24.07.2013
comment
@EricPostpischil привет! Ты там? Прочитать комментарий Дэниела Фишера. Его расширение компилятора. - person Grijesh Chauhan; 25.07.2013
comment
@GrijeshChauhan Спасибо за помощь, я пробовал с GCC версии 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1), и код отлично компилируется с флагом -pedantic -error. - person boleto; 25.07.2013
comment
Предупреждение и ошибка @GrijeshChauhan такие же, как в моем вопросе. - person boleto; 25.07.2013
comment
@boleto Хорошо, вместо предупреждения вы получили ошибку под Ubuntu с gcc4.4.3 ? Верно? - person Grijesh Chauhan; 25.07.2013
comment
@bole, чтобы подождать, скомпилируйте его как: gcc -pedantic-errors -Wall std=c99 souce.c -o exename. - person Grijesh Chauhan; 25.07.2013
comment
@GrijeshChauhan Протестировано с тремя версиями GCC на разных платформах: 4.7.1 (tdm-1) win32; 4.5.3 i686-pc-cygwin; 4.4.3 x86_64-linux-gnu; Варианты те же: gcc -pedantic-errors -Wall -std=c99 -o test main.c day.c Код компилируется без ошибок. Предупреждения: day.c: 1: предупреждение: предполагается, что массив дней содержит один элемент - person boleto; 30.07.2013
comment
@boleto :( Довольно запутанные результаты. Но дело в том, что это ошибка, за исключением компиляторов gcc. - Спасибо, Boleto! - person Grijesh Chauhan; 30.07.2013

Вы должны объявить массив в одном файле c и объявить переменную как extern в другом файле c.

person Magn3s1um    schedule 24.07.2013
comment
Да, массив должен быть определен (а не просто объявлен) в одном файле и объявлен (не определен) с extern в другом. Однако типы также должны быть совместимыми. int * и int [] несовместимы. Этот ответ не решит проблему. - person Eric Postpischil; 24.07.2013