我试图在c中创建一个字符串数组,如果我使用以下代码:

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

GCC给我“警告:来自不兼容的指针类型的赋值”。正确的做法是什么?

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


当前回答

字符串字面量是const char *。

你用圆括号也很奇怪。你的意思可能是

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

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

其他回答

在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", ...};

This assumes the size and number of strings in the initializer match up with your array dimensions. In this case, the contents of each string literal (which is itself a zero-terminated array of char) are copied to the memory allocated to strs. The problem with this approach is the possibility of internal fragmentation; if you have 99 strings that are 5 characters or less, but 1 string that's 20 characters long, 99 strings are going to have at least 15 unused characters; that's a waste of space.

你可以存储一个指向char的1维数组,而不是使用char的2维数组:

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];

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

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

如果字符串是静态的,你最好使用:

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

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

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

如果你不想跟踪数组中字符串的数量,并且想要遍历它们,只需在最后添加NULL字符串:

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

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

以下是你的一些选择:

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 -因为他们的缺点指出静态存储(存储字符串位置)的内容不能可靠地改变了(viz.未定义行为),如果你想分配non-string文字a2和a3的元素——你首先要动态地分配足够的内存,然后有自己的元素指向该内存,然后将字符复制到它,然后你必须完成后一定要释放内存。

呸——我已经开始想念c++了;)

附注:如果你需要例子,请告诉我。