Структурные указатели - доступ к массиву структур с помощью указателей - PullRequest
0 голосов
/ 16 декабря 2018

У меня есть эта простая программа:

#include <stdio.h>

struct time
{
    int hours ;
    int minutes ;
    int seconds ;
} t[2] = {1,2,3,4,5,6};

int main() {    
    struct time *tt = t;
    printf("%d\n", (*tt));
    printf("%d", *(tt+1));
}

Теперь ожидаемый вывод должен быть:

1
4

Но вывод, который я получаю, - это 2 абсолютно одинаковых адреса памяти.Я отправил эту программу другим людям, и у некоторых ожидаемый результат, а у некоторых нет.Я считаю, что это проблема с версией C или GCC.Это разрешимо?Есть ли какое-то объяснение тому, почему это происходит в моей версии C?

Самое странное, что даже после разыменования указателя он все еще печатает некоторый адрес.Как это возможно?

С другой стороны, если я изменю программу следующим образом:

$include <stdio.h>

struct time
{
    int hours ;
    int minutes ;
    int seconds ;
} t[2] = {1,2,3,4,5,6};

int main() {    
    struct time *tt = t;
    printf("%d\n", (*tt).hours);
    printf("%d", (*(tt+1)).hours);
}

Она печатает ожидаемый результат.

Какое объяснение этомуповедение?Спасибо.

Ответы [ 3 ]

0 голосов
/ 16 декабря 2018

Проблема не в компиляторе, а в вашем понимании C. Давайте скомпилируем с GCC версии 7.3.0 (Ubuntu 7.3.0-27ubuntu1 ~ 18.04):

% gcc struct_time.c      
struct_time.c: In function ‘main’:
struct_time.c:12:14: warning: format ‘%d’ expects argument of type ‘int’, 
          but argument 2 has type ‘struct time’ [-Wformat=]
     printf("%d\n", (*tt));
             ~^     ~~~~~
struct_time.c:13:14: warning: format ‘%d’ expects argument of type ‘int’,
          but argument 2 has type ‘struct time’ [-Wformat=]
     printf("%d", *(tt+1));
             ~^   ~~~~~~~

Ваш формат %dкоторый ожидает int в качестве соответствующего аргумента, и вы передаете struct time.Поведение программы не определено, поскольку спецификатор преобразования не соответствует типу фактического аргумента.

Не имеет значения , где значения находятся в памяти - их тип такжеважный.Хотя адрес tt[0] совпадает с tt[0].hours, они имеют отдельный тип.В одном вам нужна вся структура, в другом - значение, содержащееся в первом члене.

0 голосов
/ 16 декабря 2018

Он работает нормально, потому что массив используется как указатель (на 100% нормально)

, поэтому tt указывает на первый элемент массива (с индексом 0), а tt + 1 навторой (индекс 1).

Когда вы добавляете единицу к этому указателю (и этот указатель относится к указателю типа на структуру), результирующий указатель ссылается на следующую структуру этого типа.

Если вы разыменовываете указатели на структуры или союзы, используйте ->

(*tt).hours == tt -> hours и (tt + 1).hours == (tt + 1) -> hours

0 голосов
/ 16 декабря 2018

Ваш код неверен.Вот ошибка, которую должен выдавать ваш компилятор (может быть, вы не включаете предупреждения?):

error: format specifies type 'int' but the argument has type 'struct time' [-Werror,-Wformat]
    printf("%d\n", (*tt));

Вы просто не можете написать подобный код и потом жаловаться на его поведение.Вы говорите printf (), что передаете целое число, но затем передаете структуру.Может случиться что угодно.

Для бонусных баллов у вас есть проблема стиля, о которой разумный компилятор также предупредит:

error: suggest braces around initialization of subobject [-Werror,-Wmissing-braces]
} t[2] = {1,2,3,4,5,6};

Это потому, что вы инициализируете 2 структуры одним спискомномера.Это должно быть {{1,2,3},{4,5,6}}.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...