ANSI C: объявить указатель типа «массив строк» - PullRequest
0 голосов
/ 06 сентября 2018

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

struct {
  int    id;
  char   str00[10];
  char   str01[10];
  char   str03[10];
  char   str04[10];
  ...
}   myStructure;

Все strXX имеют одинаковый размер. Я хотел бы получить к ним доступ через массив (strArray), например:

strcpy(strArray[i], strValue);

Как объявить strArray?

Я использовал это:

char   (*strArray)[][10] = (void *)&myStructure.str00;

Это работает, но я должен кодировать strcpy следующим образом

strcpy((*strArray)[i], strValue);

... и мне это не нравится: -)

Есть ли другой способ объявить strArray?

Спасибо за ваши идеи и помощь.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Самый простой способ определить strArray в соответствии с запросом - сделать его массивом указателей на (первые элементы) массивов в myStructure:

char *strArray[] = { myStructure.str00, myStructure.str01, myStructure.str03, myStructure.Str04, … };

С этим определением strArray[i] инициализируется соответствующим членом структуры, таким как myStructure.str01. Обратите внимание, что myStructure.str01 будет автоматически преобразован в указатель на его первый элемент, поэтому strArray[i] является указателем на первый char в одном из массивов.

Тогда strArray[i][j] равно char j массива i.

(Кстати, вы пропускаете str02 в своем примере кода. Я не знаю почему, но сохранил это в коде выше.)

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

struct
{
    int    id;
    union
    {
        struct
        {
            char   str00[10];
            char   str01[10];
            char   str03[10];
            char   str04[10];
            ...
        };
        char strArray[number of arrays][10];
    };
} myStructure;

Это, как правило, плохой дизайн, так как он излишне запутывает. (В то время как это имеет техническую вероятность сбоя из-за заполнения между индивидуально определенными массивами, утверждения могут использоваться, чтобы гарантировать, что это не происходит, или, скорее, чтобы определить, когда это происходит.)

Чаще всего мы просто определяем строки как массив массивов:

struct
{
    int id;
    char str[number of arrays][10];
} my Structure;

Тогда члены всегда будут указываться по индексу, например myStructure.str[1], а не по отдельным именам, таким как myStructure.str01.

0 голосов
/ 06 сентября 2018

Вы почти получили его, правильный тип указателя просто char (*ptr)[10].

Наивно, вы могли бы использовать этот тип указателя для перебора элементов структуры, но это вызвало бы неопределенное поведение.Поскольку, строго говоря, указатель может указывать только на один элемент или массив, и если мы используем арифметику указателя для выхода за пределы этого единственного элемента / массива, мы вызываем неопределенное поведение.

Я еще включу пример,для демонстрации арифметики указателя массива:

// BAD CODE, it relies on undefined behavior!

#include <stdio.h>
#include <string.h>

typedef struct {
  int    id;
  char   str00[10];
  char   str01[10];
  char   str02[10];
  char   str03[10];
} myStructure;


int main(void)
{
  myStructure ms = { 0 };
  char (*ptr)[10] = &ms.str00;

  for(size_t i=0; i<4; i++)
  {
    strcpy(ptr[i], "hello ");
    strcat(ptr[i], (char[]){i+'0', '\0'});
  }

  puts(ms.str00);
  puts(ms.str01);
  puts(ms.str02);
  puts(ms.str03);

  return 0;
}

Правильное решение состоит в том, чтобы вместо этого использовать объединение, чтобы вы могли получить доступ к элементам по отдельности или в виде массива:

typedef union {
  struct              // anonymous struct, requires a standard C compiler
  {
    char str00[10];
    char str01[10];
    char str02[10];
    char str03[10];
  };
  char array[4][10];
} str_t;

typedef struct {
  int    id;
  str_t  str;
} myStructure;


strcpy(ms.str.array[i], ...); // access as array
puts(ms.str.str00); // access as individual item
...