Char ** использование и печать

В C я использую char ** провести серию строк.

Вот мой код:

char ** c;
//now to fill c with data ????

//cannot change:
printf ("%*s%s", 0, "", *c);
while (*++w)
    printf (" %s", *c);

Я не знаю, как заполнить c с данными. Как правильно? Я не могу изменить 3 строки печати, потому что они находятся во внешней функции.

3 ответа

Решение

Терминология здесь важна, я думаю. char ** не "держит" ряд строк вообще (в отличие от контейнерных объектов на языках более высокого уровня, чем C). Переменная c это просто указатель на указатель на символ, и этот символ будет первым символом в строке с нулевым символом в конце.

Эта линия мышления ведет непосредственно к решению: если c - указатель на указатель на символ, это означает, что мы должны выделить некоторую память для хранения массива строк.

Решение @DB_Monkey, опубликованное в виде комментария, пытается это сделать, но не совсем верно, поскольку подразумевает, что c[0] = "cat" копирует "кошку" в c[0], что не так - присваивание применяется к указателю, а не к строке. Лучший способ был бы:

int rows = 3;
char **c = calloc (rows,sizeof(char*));
c[0] = "cat";
c[1] = "dog";
c[2] = "mouse";

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

Ваш символ ** на самом деле является числом, которое думает, что число является адресом числа, которое является адресом действительного символа...

проще говоря:

// I am a number that has undefined value, but I pretend to point to a character.
char* myCharPointer;
// the statement above will crash(due to accessing illegal memory), or access arbitrary memory.
char myChar = *myCharPointer; 

Чтобы использовать этот указатель, вы должны его инициализировать.

char* myCharPointer = (char*)malloc(10 * sizeof(char));

теперь вы можете использовать этот указатель так же, как вы работаете с массивами, или, если хотите, с арифметикой указателей.

Обратите внимание, что malloc не устанавливает все значения в "массиве" на 0, их значения по умолчанию не определены.

Чтобы сделать то, что вы хотите, вы должны сделать следующее:

// I can store 10 "strings"
char** myArrayOfStrings = (char**)malloc(10 * sizeof(char*));
char* str0 = "Hello, world0";
char* str1 = "Hello, World1";
char* str2 = "Hello, World2";
char* str3 = "Hello, world3";
char* str4 = "Hello, world4";
char* str5 = "Hello, world5";
char* str6 = "Hello, world6";
char* str7 = "Hello, world7";
char* str8 = "Hello, world8";
char* str9 = "Hello, world9";
myArrayOfStrings[0] = str0;
myArrayOfStrings[1] = str1;
myArrayOfStrings[2] = str2;
myArrayOfStrings[3] = str3;
myArrayOfStrings[4] = str4;
myArrayOfStrings[5] = str5;
myArrayOfStrings[6] = str6;
myArrayOfStrings[7] = str7;
myArrayOfStrings[8] = str8;
myArrayOfStrings[9] = str9;
// the above is the same as
// *(myArrayOfStrings+9) = str9

Вам не обязательно иметь строки одинаковой длины, предположим, что str[0..9] на самом деле являются числами, которые хранят адрес, где первый символ этих строк находится в памяти, например

str0 = (char*)&9993039;
str1 = (char*)&9993089;

myArrayOfStrings на самом деле также является числом, в котором хранится адрес расположения первой строки, в частности myArrayOfStrings = (char**)&str0;

Очевидно, вы не будете делать это явно, как я показал, но это может быть сделано во время выполнения без особых проблем, просто сохраните строку от пользователя в буфере, затем добавьте ее в список, надеясь, что она не исчерпает себя. пространство (есть способы избежать этого).

Надеюсь, это помогло.

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

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

Вы делаете это с помощью malloc, sizeof и for петля.

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

char **c = malloc(NUMBER_OF_STRINGS * sizeof(char*));

Это делает вашу переменную c, указывающую на NUMBER_OF_STRINGS, которое является целым числом, указателем на символ.

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

/*All the space with MAX_STR= maximum string size*/
 for(i=0;i<NUMBER_OF_STRINGS;i++){
    c[i] = malloc(MAX_STR * sizeof(char));
 }

И теперь вы можете скопировать свои строки в c[i] который держит строку с MAX_STR размер или даже получить фактический char из строки, делая c[i][j] который дает вам символ j из строки i.

/*Alloc when you have the string*/
  while(fgets(buff, BUFFSIZE, stdin) != NULL){   //This is just an example of an input reading from the keyboard
       c[i] = malloc(strlen(buff) * sizeof(char));
       i++;
  }

Я использовал функцию strlen чтобы получить размер buff(бафф это просто строка). Проверьте string.h для функций работы со строками.

Поэтому я надеюсь, что это решит вашу проблему. Еще одна вещь, после каждого malloc вы должны проверить, если malloc не вернулся NULL что происходит, когда вы исчерпали виртуальную память процесса.

Надеюсь это поможет.

Другие вопросы по тегам