如何在C中创建字符串数组?

时间:2009-07-06 18:47:04

标签: c arrays string

我正在尝试在C中创建一个字符串数组。如果我使用此代码:

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

gcc给我“警告:从不兼容的指针类型分配”。这样做的正确方法是什么?

编辑:我很好奇为什么这会给编译器警告,因为如果我printf(a[1]);,它会正确打印“hmm”。

14 个答案:

答案 0 :(得分:207)

如果您不想更改字符串,则只需执行

即可
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个数组,然后将静态字符串的内容复制到其中。

答案 1 :(得分:161)

有几种方法可以在C中创建字符串数组。如果所有字符串的长度相同(或者至少具有相同的最大长度),则只需声明一个2-d数组的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的指针数组,而不是使用二维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");

BTW,

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

将a声明为指向14元素char数组的2元素指针数组。

答案 2 :(得分:84)

的Ack!常量字符串:

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

如果我没记错的话。

哦,你想使用strcpy进行分配,而不是使用=运算符。 strcpy_s更安全,但它既不是C89也不是C99标准。

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

更新: Thomasstrlcpy是可行的方法。

答案 3 :(得分:12)

以下是您的一些选择:

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。原因是a2和a3是指针数组,你可以使它们的元素(即指针)指向任何存储,而a1是“字符数组”的数组,所以每个元素都是一个“拥有”它的数组自己的存储(这意味着当它超出范围时会被破坏) - 你只能将东西复制到它的存储中。

这也带来了使用a2和a3的缺点 - 因为它们指向静态存储(存储字符串文字),其内容无法可靠地更改(即未定义的行为),如果要指定非-string文字到a2或a3的元素 - 你首先必须动态分配足够的内存,然后让它们的元素指向这个内存,然后将字符复制到它 - 然后你必须确保释放内存时完成。

Bah - 我已经错过了C ++;)

P.S。如果您需要示例,请告诉我。

答案 4 :(得分:10)

在ANSI C中:

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

答案 5 :(得分:10)

或者你可以声明一个结构类型,它包含一个字符arry(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;

答案 6 :(得分:9)

如果您不想跟踪数组中的字符串数并希望迭代它们,只需在最后添加NULL字符串:

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

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

答案 7 :(得分:8)

字符串文字是const char * s。

你对括号的使用很奇怪。你可能意味着

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

声明一个包含两个常量字符指针的数组,并将它们初始化为两个硬编码字符串常量。

答案 8 :(得分:8)

如果字符串是静态的,那么最好用:

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

虽然不是基本ANSI C的一部分,但您的环境很可能支持语法。这些字符串是不可变的(只读),因此在许多环境中使用比动态构建字符串数组更少的开销。

例如,在小型微控制器项目中,此语法使用程序存储器而不是(通常)更珍贵的RAM内存。 AVR-C是支持这种语法的示例环境,但大多数其他语言也是如此。

答案 9 :(得分:3)

您的代码正在创建一个函数指针数组。尝试

char* a[size];

char a[size1][size2];

代替。

请参阅wikibooks至arrayspointers

答案 10 :(得分:1)

你好,你可以试试这个:

import MyForm from './MyForm';
<MyForm onSubmit={() => console.log("submit")} loading />

如果你想要的话,在c中使用字符串数组的一个很好的例子

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

答案 11 :(得分:0)

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");
}

在这里试试!!!

答案 12 :(得分:0)

我在某种程度上缺少更多动态字符串数组,其中字符串的数量可能因运行时选择而异,但其他字符串应该是固定的。

我最终编码了这样的代码片段:

#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选择指向数组字符串的指针,count使用_countof函数获取字符串数量。 (类似于sizeof(arr) / sizeof(arr[0]))。

使用A2T宏进行unicode转换还有额外的Ansi,但对于你的情况,这可能是可选的。

答案 13 :(得分:-6)

一个好方法是定义一个你自己的字符串。

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

真的那么简单。