Как создать массив строк в C?

Я пытаюсь создать массив строк в C. Если я использую этот код:

char (*a[2])[14];
a[0]="blah";
a[1]="hmm";

gcc выдает "предупреждение: присваивание из несовместимого типа указателя". Как правильно это сделать?

редактировать: мне любопытно, почему это должно выдавать предупреждение компилятора, так как если я делаю printf(a[1]);, он правильно печатает "хмм".

Ответ 1

Если вы не хотите менять строки, вы можете просто сделать

const char *a[2];
a[0] = "blah";
a[1] = "hmm";

Когда вы сделаете это так, вы выделите массив из двух указателей на const char. Затем эти указатели будут установлены на адреса статических строк "blah" и "hmm".

Если вы хотите изменить фактическое содержимое строки, вам нужно сделать что-то вроде

char a[2][14];
strcpy(a[0], "blah");
strcpy(a[1], "hmm");

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

Ответ 2

Существует несколько способов создания массива строк в C. Если все строки будут иметь одинаковую длину (или, по крайней мере, иметь одинаковую максимальную длину), вы просто объявляете двумерный массив char и назначаете при необходимости:

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1];
...
strcpy(strs[0], aString); // where aString is either an array or pointer to char
strcpy(strs[1], "foo");

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

char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};

Это предполагает, что размер и количество строк в инициализаторе совпадают с размерами вашего массива. В этом случае содержимое каждого строкового литерала (который сам по себе является массивом char с нулевым символом в конце) копируется в память, выделенную для strs. Проблема этого подхода заключается в возможности внутренней фрагментации; если у вас есть 99 строк длиной не более 5 символов, но 1 строка длиной не более 20 символов, 99 строк будут содержать не менее 15 неиспользуемых символов; это пустая трата пространства.

Вместо того, чтобы использовать двумерный массив символов char, вы можете сохранить 1-й массив указателей на char:

char *strs[NUMBER_OF_STRINGS];

Обратите внимание, что в этом случае вы только выделяете память для хранения указателей на строки; память для самих строк должна быть выделена в другом месте (либо в виде статических массивов, либо с помощью malloc() или calloc()). Вы можете использовать список инициализаторов, как в предыдущем примере:

char *strs[NUMBER_OF_STRINGS] = {"foo", "bar", "bletch", ...};

Вместо того, чтобы копировать содержимое строковых констант, вы просто сохраняете указатели на них. Обратите внимание, что строковые константы могут быть недоступны для записи; Вы можете переназначить указатель следующим образом:

strs[i] = "bar";
strs[i] = "foo"; 

Но вы не сможете изменить содержимое строки; т.е.

strs[i] = "bar";
strcpy(strs[i], "foo");

может быть запрещено

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

strs[i] = malloc(strlen("foo") + 1);
strcpy(strs[i], "foo");

Кстати,

char (*a[2])[14];

Объявляет как 2-элементный массив указателей на 14-элементные массивы char.

Ответ 3

Ack! Константные строки:

const char *strings[] = {"one","two","three"};

Если я правильно помню.

О, и вы хотите использовать strcpy для назначения, а не оператор =. strcpy_s является более безопасным, но он ни в C89, ни в стандартах C99.

char arr[MAX_NUMBER_STRINGS][MAX_STRING_SIZE]; 
strcpy(arr[0], "blah");

Обновление: Томас говорит, что strlcpy - это путь.

Ответ 4

Вот некоторые из ваших вариантов:

char a1[][14] = { "blah", "hmm" };
char* a2[] = { "blah", "hmm" };
char (*a3[])[] = { &"blah", &"hmm" };  // only since you brought up the syntax -

printf(a1[0]); // prints blah
printf(a2[0]); // prints blah
printf(*a3[0]); // prints blah

Преимущество a2 заключается в том, что вы можете делать следующее со строковыми литералами

a2[0] = "hmm";
a2[1] = "blah";

А для a3 вы можете сделать следующее:

a3[0] = &"hmm";
a3[1] = &"blah";

Для a1 вам придется использовать strcpy() (еще лучше strncpy()) даже при назначении строковых литералов. Причина в том, что a2 и a3 являются массивами указателей, и вы можете сделать так, чтобы их элементы (то есть указатели) указывали на любое хранилище, тогда как a1 - это массив "массив символов", поэтому каждый элемент является массив, который "владеет" своим собственным хранилищем (что означает, что он уничтожается, когда выходит из области видимости) - вы можете копировать только содержимое в свое хранилище.

Это также приводит нас к недостатку использования a2 и a3 - поскольку они указывают на статическое хранилище (где хранятся строковые литералы), содержимое которого не может быть надежно изменено (а именно, неопределенное поведение), если вы хотите назначить нестроковые литералы для элементов a2 или a3 - сначала вам нужно будет динамически выделить достаточно памяти, а затем их элементы указывают на эту память, а затем скопировать в нее символы - и тогда вы должны быть уверены, что чтобы освободить память, когда закончите.

Бах - я уже скучаю по C++;)

постскриптум Дайте мне знать, если вам нужны примеры.

Ответ 5

В ANSI C:

char* strings[3];
strings[0] = "foo";
strings[1] = "bar";
strings[2] = "baz";

Ответ 6

Или вы можете объявить тип структуры, который содержит символьную строку (1 строку), они создают массив структур и, следовательно, многоэлементный массив

typedef struct name
{
   char name[100]; // 100 character array
}name;

main()
{
   name yourString[10]; // 10 strings
   printf("Enter something\n:);
   scanf("%s",yourString[0].name);
   scanf("%s",yourString[1].name);
   // maybe put a for loop and a few print ststements to simplify code
   // this is just for example 
 }

Одним из преимуществ этого по сравнению с любым другим методом является то, что он позволяет сканировать непосредственно в строку без использования strcpy;

Ответ 7

Строковые литералы const char * s.

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

const char *a[2] = {"blah", "hmm"};

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

Ответ 8

Если вы не хотите отслеживать количество строк в массиве и хотите перебирать их, просто добавьте строку NULL в конец:

char *strings[]={ "one", "two", "three", NULL };

int i=0;
while(strings[i]) {
  printf("%s\n", strings[i]);
  //do something
  i++;
};

Ответ 9

Если строки статичны, вам лучше всего:

const char *my_array[] = {"eenie","meenie","miney"};

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

Например, в небольших проектах микроконтроллера этот синтаксис использует память программ, а не (обычно) более ценную память RAM. AVR-C является примером среды, поддерживающей этот синтаксис, но так же, как и большинство других.

Ответ 10

В вашем коде создается массив указателей на функции. Попробуйте

char* a[size];

или

char a[size1][size2];

вместо.

Смотрите wikibooks на arrays и pointers

Ответ 11

Здравствуйте, вы можете попробовать это ниже:

 char arr[nb_of_string][max_string_length]; 
 strcpy(arr[0], "word");

хороший пример использования массива строк в c, если вы этого хотите

#include <stdio.h>
#include <string.h>


int main(int argc, char *argv[]){

int i, j, k;

// to set you array
//const arr[nb_of_string][max_string_length]
char array[3][100];

char temp[100];
char word[100];

for (i = 0; i < 3; i++){
    printf("type word %d : ",i+1);
    scanf("%s", word);
    strcpy(array[i], word);
}

for (k=0; k<3-1; k++){
    for (i=0; i<3-1; i++)
    {
        for (j=0; j<strlen(array[i]); j++)
        {
            // if a letter ascii code is bigger we swap values
            if (array[i][j] > array[i+1][j])
            {
                strcpy(temp, array[i+1]);
                strcpy(array[i+1], array[i]);
                strcpy(array[i], temp);

                j = 999;
            }

            // if a letter ascii code is smaller we stop
            if (array[i][j] < array[i+1][j])
            {
                    j = 999;
            }

        }
    }
}

for (i=0; i<3; i++)
{
    printf("%s\n",array[i]);
}

return 0;
}

Ответ 12

char name[10][10]
int i,j,n;//here "n" is number of enteries
printf("\nEnter size of array = ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("\nEnter name = ");
        scanf("%s",&name[i]);
    }
}
//printing the data
for(i=0;i<n;i++)
{
    for(j=0;j<1;j++)
    {
        printf("%d\t|\t%s\t|\t%s",rollno[i][j],name[i],sex[i]);
    }
    printf("\n");
}

Здесь попробуйте это!!!

Ответ 13

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

Я закончил фрагмент кода кода следующим образом:

#define INIT_STRING_ARRAY(...)          \
    {                                   \
        char* args[] = __VA_ARGS__;     \
        ev = args;                      \
        count = _countof(args);         \
    }

void InitEnumIfAny(String& key, CMFCPropertyGridProperty* item)
{
    USES_CONVERSION;
    char** ev = nullptr;
    int count = 0;

    if( key.Compare("horizontal_alignment") )
        INIT_STRING_ARRAY( { "top", "bottom" } )

    if (key.Compare("boolean"))
        INIT_STRING_ARRAY( { "yes", "no" } )

    if( ev == nullptr )
        return;

    for( int i = 0; i < count; i++)
        item->AddOption(A2T(ev[i]));

    item->AllowEdit(FALSE);
}

char** ev выбирает указатель на строки массива, и подсчет числа элементов берет с помощью функции _countof. (Подобно sizeof(arr) / sizeof(arr[0])).

И есть дополнительный Ansi для преобразования unicode с использованием макроса A2T, но это может быть необязательным для вашего случая.

Ответ 14

Хорошим способом является определение вашей собственной личности.

#include <stdio.h>
typedef char string[]
int main() {
    string test = "string";
    return 0;
}

Это действительно так просто.