Създаване на масив за съхранение на масиви от символни масиви в 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.

Това изглежда неправилно, тъй като когато се опитам да осъществя достъп и да отпечатам съдържанието на масива за моментни снимки, той отпечатва само информацията от най-новия arrayOfStrings. Идеята, която възнамерявах с това, беше да съхраня адреса на мястото, където arrayOfChars сочи в запис на масива за моментни снимки, за да мога да получа достъп до него по-късно.

В момента достъпът до запис в масива за моментни снимки се осъществява по следния начин:

arrayOfArraysOfChars[historicalIndex][indexOfTargetChar]

Има няколко въпроса, на които търся отговор:

  1. Методът, който очертах, подходящ ли е за това, което се опитвам да направя, или има недостатък в цялостната ми логика?
  2. Какво правя грешно с текущия си код и как да го поправя?
  3. Има ли по-добър начин да направите това и ако да, как работи инициализацията на масивите, добавянето към масивите и четенето от масивите?

--edit 4/18-- Част от проблема е, че задавам указатели в 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