Создание массива для хранения массивов символьных массивов в C

Мой C на данный момент немного более чем ржавый, поэтому я не могу создать что-то, что, по моему мнению, должно быть довольно простым.

Позвольте мне ссылаться на массивы символов как на строки для этого поста. Это прояснит ситуацию и для меня, и для вас.

У меня есть массив, который может содержать 1 или более строк. Например {"ab", "cd", "ef"}. Я хочу создать еще один массив для хранения нескольких версий массива строк. Что-то вроде {{"ab", "cd", "ef"}, {"gh", "ij"}, {"kl"}}.

Что у меня есть прямо сейчас:

char *arrayOfStrings[50]; // a single array to hold multiple strings
char **arrayOfArraysOfStrings[10]; // array to hold multiple snapshots of arrayOfStrings

Массив строк меняется со временем, и я использую массив массивов строк, чтобы в основном хранить исторические снимки arrayOfStrings. Моя проблема возникает, когда мне нужно получить доступ к массиву снимков для данных. Это код, который я должен поместить в массив моментальных снимков:

arrayOfArraysOfStrings[input_index] = arrayOfStrings; // you can assume input_index is updated correctly, I've already checked that.

Это кажется неверным, поскольку, когда я пытаюсь получить доступ к содержимому массива моментальных снимков и распечатать его, он выводит информацию только из самых последних массивов строк. Идея, к которой я стремился, заключалась в том, чтобы сохранить адрес, на который указывает arrayOfChars, в записи массива моментальных снимков, чтобы я мог получить к нему доступ позже.

Прямо сейчас доступ к записи в массиве снимков осуществляется следующим образом:

arrayOfArraysOfChars[historicalIndex][indexOfTargetChar]

Есть несколько вопросов, на которые я хочу ответить:

  1. Подходит ли метод, который я изложил, для того, что я пытаюсь сделать, или в моей общей логике есть изъян?
  2. Что я делаю не так с моим текущим кодом и как это исправить?
  3. Есть ли лучший способ сделать это, и если да, то как работает инициализация массивов, добавление к массивам и чтение из массивов?

--edit 18/4-- Часть проблемы заключается в том, что я устанавливаю указатели в arrayOfArraysOfStrings так, чтобы они указывали на то же самое, на что указывает arrayOfStrings. Это плохо, так как arrayOfStrings редактируется. Мне нужен какой-то способ дублировать 2D-массив... Предпочтительно, просто выделив новый блок памяти для arrayOfStrings, чтобы указать на него.


person Dae314    schedule 18.04.2013    source источник


Ответы (5)


У вас слишком много указателей в обоих ваших массивах.

char arrayOfChars[50]; // a single array of characters
char *arrayOfArraysOfChars[10]; // array to hold multiple single arrays of characters

Поскольку arrayOfChars используется как буфер (новые данные всегда идут туда первыми), вам необходимо сохранить копию строки в arrayOfArrays. Здесь должна помочь функция POSIX strdup.

Обратите внимание, что & и * являются противоположностями, поэтому &* и *& абсолютно ничего не делают.

Вы также можете сделать arrayOfArrays буквально этим.

char arrayOfChars[50]; // a single array of characters
char arrayOfArraysOfChars[10][50]; // array to hold multiple single arrays of characters

С этой настройкой вы должны использовать strcpy для копирования данных в arrayOfArrays.


Прочитав ваше редактирование, я думаю, вам нужно начать с очень простого. И FWIW имена переменных неправильные венгерские.

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

enum { BUFSZ = 50 };
char buf[BUFSZ + 1];

Затем вы можете использовать его с fgets или чем-то еще.

fgets(buf, BUFSZ, infile);

Чтобы сохранить их в массиве, я бы использовал strdup для его автоматической обрезки. Если строки будут состоять в основном из 2 символов, я не хочу, чтобы для каждого из них использовалось 48 дополнительных байтов. Итак, массив указателей на символы (строки).

enum { STRVSZ = 40 };
char *strv[STRVSZ + 1];
int i;
i = 0;
strv[i] = strdup(buf);
strv[i+1] = NULL; // This makes it an "argv-style" NULL-terminated array of strings
++i; // i is now the index of the next element, and a count of elements already added

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

Теперь, чтобы создать их списки, мы делаем то же самое снова. Но нет функции типа strdup для создания дубликата массива указателей, поэтому мы должны разделить выделение и копирование.

enum { STRVVSZ = 20 };
char **strvv[STRVVSZ + 1];
int j;
j = 0;
strvv[j] = calloc(i+1, sizeof *strvv[j]); // assuming i is the count of elements 
memcpy(strvv[j], strv, i * sizeof *strvv[j]);
++j; // j is now the index of the next string-pointer array in the array-of-same,
     // and a count of elements already added.

Теперь мои имена такие же глупые, как и ваши, но они короче!

person luser droog    schedule 18.04.2013
comment
Это очень близко к решению проблемы, но не совсем понял. На самом деле мне нужен массив, содержащий несколько одиночных массивов символов (я буду называть массивы символов строками), но мне также нужен массив, содержащий несколько массивов строк. Дайте мне минутку, чтобы обновить OP более ясным языком. - person Dae314; 19.04.2013
comment
Это по крайней мере теоретически именно то, что мне было нужно :). Я не уверен, почему memcpy не работает, но я опубликую подробности в отдельном вопросе. Что касается масштабов этого вопроса, это отличный ответ. - person Dae314; 19.04.2013
comment
Я отредактировал, добавив ++i; и ++j; и комментарии о важности этих строк. - person luser droog; 19.04.2013

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

char array[] = {"somestringhere"};

теперь вы хотите хранить такие массивы в другом массиве. это просто:

char* array1[];

в массиве1 будут храниться значения типа char*, то есть адреса массивов символов. теперь вы хотите сохранить их в другом массиве,

char** array2[];

это массив [адреса массивов] теперь, все, что вам нужно сделать, это;

array1[0] = array; //same as: array1[0] = *array[0];
array2[0] = *array1[0];

Теперь у вас есть все, что вам нужно. Надеюсь, вы ясно, до глубины души. :)

person Community    schedule 18.04.2013
comment
Это также помогло прояснить, что я пытаюсь сделать, спасибо. Теперь просто нужно выяснить, как изменить указатель. - person Dae314; 19.04.2013

Этот пример был сделан с помощью turbo c+ 1.01 dos и работает также в версии 3.0 dos.

char * text[] = {
  "message1",
  "message2",
  "message3"
};
person steven tahner    schedule 06.10.2014

Обратите внимание, что в ваших примерах показаны массивы указателей. Если вам нужны массивы массивов (многомерные массивы), укажите все размеры в определении массива.

char sentences[500][42]; /* sentences is an array of 500 elements.
                         ** each element is itself an array
                         ** capable of holding strings up to length 41 */
person pmg    schedule 18.04.2013
comment
Вы могли бы прочитать раздел 6 часто задаваемых вопросов о comp.lang.c, который объясняет намного лучше, чем я когда-либо мог почему массивы не являются указателями и указатели не являются массивами. - person pmg; 19.04.2013

при сохранении текста в файле .c или .h, содержащем более одной строки текста, что эквивалентно идее массива массивов символов. можно сделать это:

char * text[] = {
  "message1",
  "message2",
  "message3"
};

также можно использовать char *text[], char near *text[], char far *text[], char huge *text[]. должен иметь звездочку или звездочку для указателя.

цикл for можно использовать для отображения текста:

char i; // int type can also be used
for (i = 0, i < 3; i++)
  printf("%s\n", text[i]);

другие петли:

char i = 0;  // may not be zero when declared as "char i;" only
while (i < 3) {
  printf("%s\n", text[i]);
  i++;
 }

or

char i = 0;  // may not be zero when declared as "char i;" only
do {
 printf("%s\n", text[i]);
 i++;
} while (i < 3);
person steven tahner    schedule 16.09.2014