Как правильно распечатать все элементы массива типа struct в C? - PullRequest
1 голос
/ 19 апреля 2020

У меня есть структура:

typedef enum
{
    Cat = 1,
    Dog,
    GuineaPig,
    Parrot,
} SPECIES;

#define MaxNameLength 25
#define MaxNrAnimals 20

typedef struct
{
    char    Name[MaxNameLength];
    SPECIES Species;
    int     Age;
} ANIMAL;

Я попытался напечатать только строку имени, используя:

ANIMAL animals[MaxNrAnimals];
for (int j = 0; j < sizeof(animals) / sizeof(animals[0]); j++) {
    printf("%c", animals[j].Name);
}

Это возвращает:

@ dê¼ `<` Ä¿╠≡8 \ Çñ╚∞ </p>

независимо от того, заполнен ли массив «животные» или нет. Как мне go правильно распечатать каждый существующий элемент имени массива?

Ответы [ 3 ]

2 голосов
/ 19 апреля 2020
ANIMAL animals[MaxNrAnimals];
for (int j = 0; j <MaxNrAnimals ; j++) {
printf("%s\n", animals[j].Name);
     }

попробуйте

2 голосов
/ 19 апреля 2020

Другие ответы совершенно правильны в решении вашей проблемы. Я хотел добавить немного предыстории.

Строка символов C - это адрес непрерывной последовательности в памяти байтов, содержащих значения символов - ie a char*. Причина, по которой ваши выходные данные содержат причудливые символы, заключается в том, что вы сказали printf обрабатывать адрес памяти, указывающий на имя животного, как один символ.

Если мы напишем такой код,

#include <stdio.h>

int main() {
  char *str = "blah blah blah";
  printf("%c\n", str);
}

Вменяемая компиляция предупредит вас, что вы. приведение вашего адреса в неподходящий тип:

$ gcc -o ct t.c
t.c:5:18: warning: format specifies type 'int' but the argument has type
      'char *' [-Wformat]
  printf("%c\n", str);
          ~~     ^~~
          %s
1 warning generated.

Следует ожидать проблем с любым написанным вами кодом, который выдает предупреждения при компиляции. Код все еще может завершить компиляцию sh, но это не значит, что он будет работать правильно. Немедленно исправьте все предупреждения компилятора - C - сложный язык, и если вы проигнорируете предупреждения компилятора, вы, скорее всего, получите непреднамеренное поведение, весьма вероятно в, казалось бы, не связанных частях кода.

В моем случае я получаю нечто подобное, потому что первый байт адреса строки не является допустимой печатаемой последовательностью символов:

$ ./ct
�

Изучение вывода в шестнадцатеричном формате помогает нам увидеть \n (значение ascii 0a в моем окружении, также называемое "newlline", также называемое "перевод строки" в ascii). Непосредственно после этого это шестнадцатеричное значение значения вывода «% c» - 0xa2. Так как это не входит в стандартную 7-битную таблицу ascii, и мой терминал настроен на Unicode, этот символ недопустим и доступен для печати, поэтому отображается символ .

$ ./ct | hexdump
0000000 a2 0a
0000002

Если мы изменим %c на %s, мы больше не получим предупреждение компилятора, и код работает нормально.

$ cat t.c
#include <stdio.h>

int main() {
  char *str = "blah blah blah";
  printf("%s\n", str);
}

$ gcc -o ct t.c
[ no output ]

$ ./ct
blah blah blah

$ ./ct | hexdump
0000000 62 6c 61 68 20 62 6c 61 68 20 62 6c 61 68 0a
000000f

Я включил hexdump на случай, если вы захотите увидеть, как моя строка blah blah blah\n показывается в байтовом выражении.

2 голосов
/ 19 апреля 2020

Спецификатор формата %c используется для печати символа single ; для символов строки следует использовать формат %s. Кроме того, вы можете рассмотреть возможность добавления новой строки после каждого имени. Следующие изменения помогут:

ANIMAL animals[MaxNrAnimals];
for (int j = 0; j < sizeof(animals) / sizeof(animals[0]); j++) {
//  printf("%c", animals[j].Name);
    printf("%s\n", animals[j].Name);
}

Примечание. Чтобы формат %s работал, каждое поле Name должно быть строкой, определенной nul .

...