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
что происходит, когда вы исчерпали виртуальную память процесса.
Надеюсь это поможет.