Я пытаюсь создать массив строк в C. Если я использую этот код:
char (*a[2])[14];
a[0]="blah";
a[1]="hmm";
gcc выдает «предупреждение: присваивание из несовместимого типа указателя». Как правильно это сделать?
редактировать: мне любопытно, почему это должно выдавать предупреждение компилятора, так как если я это сделаю printf(a[1]);
, он правильно печатает «хмм».
char (*a[2])[14]
: массив из двух указателей на массив из 14 символов.char (*a[2])[14]
- начинай сa
, двигайся вправо: «массив из двух», двигайся влево: «указатель на», завершена скобка, так что читайте справа: «массив из четырнадцати», читайте слева: «символ» ... сложите его вместе, и мы получим «массив двух указателей на массивы из четырнадцати символов»char *str
а неchar* str
. Исходя из опыта Delphi / Pascal, я очень привык к последнему пути, пока не наткнулся на более сложные типы. Первый способ все еще выглядит уродливым, но делает обозначение типов более согласованным (IMO).Ответы:
Если вы не хотите менять строки, то вы можете просто сделать
Когда вы сделаете это так, вы выделите массив из двух указателей
const char
. Эти указатели затем будут установлены на адреса статических строк"blah"
и"hmm"
.Если вы хотите иметь возможность изменять фактическое содержимое строки, вы должны сделать что-то вроде
Это позволит выделить два последовательных массива по 14
char
с каждый, после чего содержимое статических строк будет скопировано в них.источник
Есть несколько способов создать массив строк в C. Если все строки будут иметь одинаковую длину (или, по крайней мере, иметь одинаковую максимальную длину), вы просто объявляете двумерный массив char и назначаете при необходимости:
Вы также можете добавить список инициализаторов:
Это предполагает, что размер и количество строк в инициализаторе совпадают с размерами вашего массива. В этом случае содержимое каждого строкового литерала (который сам по себе является массивом char с нулевым символом в конце) копируется в память, выделенную для strs. Проблема этого подхода заключается в возможности внутренней фрагментации; если у вас есть 99 строк длиной не более 5 символов, но 1 строка длиной не более 20 символов, 99 строк будут содержать не менее 15 неиспользуемых символов; это пустая трата пространства.
Вместо того, чтобы использовать двумерный массив символов char, вы можете сохранить 1-й массив указателей на char:
Обратите внимание, что в этом случае вы только выделяете память для хранения указателей на строки; память для самих строк должна быть выделена в другом месте (либо в виде статических массивов, либо с помощью
malloc()
илиcalloc()
). Вы можете использовать список инициализаторов, как в предыдущем примере:Вместо того, чтобы копировать содержимое строковых констант, вы просто сохраняете указатели на них. Обратите внимание, что строковые константы могут быть недоступны для записи; Вы можете переназначить указатель следующим образом:
Но вы не сможете изменить содержимое строки; т.е.
может быть не разрешено
Вы можете использовать
malloc()
для динамического выделения буфера для каждой строки и копирования в этот буфер:КСТАТИ,
Объявляется как 2-элементный массив указателей на 14-элементные массивы char.
источник
malloc
звонка.T [N]
преобразуется в выражение типаT *
, а значением выражения является адрес первого элемента. Поэтому, если вы написалиstr = "foo"
, вы бы попытались присвоить"foo"
массиву адрес первого символаstr
, что не работает. Смотрите этот ответ для более подробной информации.char *strs[NUMBER_OF_STRINGS] = {0};
Это помогает избежать проблем в будущем инициализацииstrs
вNULL
. Многие люди читают этот пост, когда Google делает поиск по массиву строк в C.Ack! Постоянные строки:
Если я правильно помню.
Да, и вы хотите использовать strcpy для присваивания, а не оператор =. strcpy_s безопаснее, но его нет ни в C89, ни в стандартах C99.
Обновление: Томас говорит,
strlcpy
что это путь.источник
Вот некоторые из ваших вариантов:
Преимущество в
a2
том, что вы можете делать следующее со строковыми литераламиИ для
a3
вас могут сделать следующее:Для
a1
вас придется использоватьstrcpy()
(еще лучшеstrncpy()
) даже при назначении строковых литералов. Причина в томa2
, что иa3
являются массивами указателей, и вы можете сделать так, чтобы их элементы (то есть указатели) указывали на любое хранилище, тогдаa1
как это массив «массив символов», и поэтому каждый элемент является массивом, который «владеет» своим собственным хранилищем ( что означает, что он уничтожается, когда выходит из области видимости) - вы можете только скопировать материал в его хранилище.Это также приводит нас к недостатку использования
a2
иa3
- поскольку они указывают на статическое хранилище (где хранятся строковые литералы), содержимое которого не может быть надежно изменено (то есть неопределенное поведение), если вы хотите назначить нестроковые литералы для элементыa2
илиa3
- сначала вам нужно будет динамически распределить достаточно памяти, а затем их элементы будут указывать на эту память, а затем копировать в нее символы - и тогда вам нужно будет обязательно освободить память, когда закончите.Бах - я уже скучаю по С ++;)
ps дайте мне знать, если вам нужны примеры.
источник
Или вы можете объявить тип структуры, который содержит символьный массив (1 строка), они создают массив структур и, таким образом, многоэлементный массив
Одним из преимуществ этого по сравнению с любым другим методом является то, что он позволяет сканировать непосредственно в строку без использования
strcpy
;источник
В ANSI C:
источник
char* foo, bar;
какой типbar
?Если строки статические, лучше всего использовать:
Хотя это не является частью базового стандарта ANSI C, скорее всего, ваша среда поддерживает синтаксис. Эти строки являются неизменяемыми (только для чтения) и, следовательно, во многих средах используют меньше служебных данных, чем динамическое построение массива строк.
Например, в небольших проектах микроконтроллеров этот синтаксис использует программную память, а не (обычно) более ценную оперативную память. AVR-C - это пример среды, поддерживающей этот синтаксис, но также и большинство других.
источник
Если вы не хотите отслеживать количество строк в массиве и хотите перебирать их, просто добавьте строку NULL в конце:
источник
Строковые литералы
const char *
s.И ваше использование скобок странно. Вы, наверное, имеете в виду
который объявляет массив из двух указателей на постоянные символы и инициализирует их, чтобы они указывали на две жестко закодированные строковые константы.
источник
Ваш код создает массив указателей на функции. Пытаться
или
вместо.
Смотрите викибуки к массивам и указателям
источник
привет, вы можете попробовать это ниже:
хороший пример использования массива строк в c, если вы хотите
источник
Вот попробуй это !!!
источник
Мне не хватало как-то более динамического массива строк, где количество строк можно варьировать в зависимости от выбора во время выполнения, но в противном случае строки должны быть исправлены.
Я закончил кодировать фрагмент кода, как это:
char** ev
выбирает указатель на строки массива, а count выбирает количество строк с помощью_countof
функции. (Аналогичноsizeof(arr) / sizeof(arr[0])
).И есть дополнительное преобразование анси в юникод с использованием
A2T
макроса, но это может быть необязательным для вашего случая.источник
Хороший способ - определить строку самостоятельно.
Это действительно так просто.
источник
;
, и как это создает массив строк ?