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


263

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

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

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

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

c  arrays  string 

12
仅作记录,char (*a[2])[14]是两个指针数组,指向14个字符的数组。
avakar,2009年

4
我认为这是指向两个字符xD数组的十四个指针
fortran

74
我读过的有关解密C类型的最有用的建议:“从名称开始,在可能的情况下向右阅读,在必须的情况下向左”:char (*a[2])[14]-从开始a,向右移动:“两个数组”,向左移动:“指针指向”,括号完整,所以右读:“十四个字符的数组”,左读:“ char” ...放在一起,我们得到“ a是两个指针的数组,指向十四个字符的数组”
Mark K Cowan

4
@dotancohen:这个技巧最终说服了我将指针写为char *str而不是char* str。来自Delphi / Pascal的背景,我非常习惯于后者,直到遇到更复杂的类型为止。前一种方法在我看来仍然很难看,但是使类型符号更一致(IMO)。
Mark K Cowan

@MarkKCowan,太神奇了!谢谢!:)
埃森博士

Answers:


232

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

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

这将分配两个连续的数组,char每个数组14 s,之后将静态字符串的内容复制到其中。


185

有几种方法可以在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数组)的内容都将复制到分配给str的内存中。这种方法的问题是内部碎片的可能性。如果您有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");

顺便说一句,

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

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


3
@Slater:是的,如果是malloc通话的结果。
John Bode 2012年

感谢您提供非常详细的答案。这真的帮助了我。
cokedude 2014年

1
为什么我们只能在声明为2D数组的String数组上使用strcpy。为什么标准分配失败?
2014年

4
@AndrewS:完整的答案不适合注释,但基本上,这是C处理数组表达式的一种人工产物。在大多数情况下,type的表达式将T [N]转换为type 的表达式T *,并且表达式的值是第一个元素的地址。因此,如果您编写了str = "foo",您将尝试将的第一个字符的地址分配给"foo"数组str,这是行不通的。有关更多详细信息,请参见此答案
约翰·博德2014年

@JohnBode您可以添加一些小的调整吗?char *strs[NUMBER_OF_STRINGS] = {0}; 通过初始化strs为,有助于防止将来出现问题NULL。很多人看到这篇文章的时候千万谷歌在C.字符串数组搜索
cokedude

94

阿克!常量字符串:

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

如果我没记错的话。

哦,您要使用strcpy进行赋值,而不要使用=运算符。strcpy_s更安全,但C89和C99标准都没有。

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

更新: 托马斯说这strlcpy是要走的路。


那是C99吗?我认为ANSI C不可行
。– Noldorin

6
C89和C99都有可能。是否使用const也无关紧要,尽管前者是首选。
avakar,2009年

1
好吧,const是新的,您以前必须指定外部数组的大小(在这种情况下为3),但否则这是完全可以接受的K&RC。我有一本版权为1984年的旧C书籍,其中的一节显示了如何做这个。他们称其为“参差不齐的数组”。当然,它没有“操作员”,而strcpy_s对我来说是新的。
TED

6
strcpy_s是Microsoft函数。应该避免使用它,因为它不在标准C中
。– Cromulent

5
strcpy_s和其他“安全功能”被标准化为ISO / IEC TR 24731(这是ISO发布的标准,因此不能免费在线获得;最新的草案是open-std.org/jtc1/sc22/wg14/www /docs/n1225.pdf
的Pavel Minaev

14

以下是您的一些选择:

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())。原因是a2a3是指针数组,可以使它们的元素(即指针)指向任何存储,而是a1“字符数组”的数组,因此每个元素都是“拥有”自己的存储的数组(这意味着它超出范围时会被销毁)-您只能将内容复制到其存储中。

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

Bah-我已经想念C ++了;)

ps让我知道您是否需要示例。


我需要一个Arduino项目的字符串数组。最后,我使用了a2样式。我最初尝试使用a1样式将我的字符串数组定义为char a1 [] [2] = {“ F3”,“ G3” ... etc。},因为它打算存储2个字符的长字符串。这给出了意外的输出,因为我忘记了空终止符,这意味着每个字符串的大小至少应为3,才能存储2个字符。使用a2样式,我不需要指定字符串的长度,它也可以容纳不同的字符串长度,因此我决定坚持使用:-)
Jeromy Adofo

char(* a3 [])[] = {&“ blah”,&“ hmm”}; =>在g ++ Apple LLVM版本9.1.0中不起作用,但在gcc中起作用
1234年

12

或者,您可以声明一个包含字符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


10

在ANSI C中:

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

8
@Zifre:我完全不同意。它是类型的一部分-在这种情况下是“字符指针”。无论如何,您会说什么...它是变量名的一部分?我已经看到许多有能力的程序员使用这种风格。
Noldorin

14
我想指出的是,对于其他阅读此书的人,Bjarne Stroustrup将*标记为...
MirroredFate 2013年

1
@MirroredFate:正确。实际上,据我所知,推荐使用C ++进行实践。从语义上说,由于标识符的使用方式,将它放在标识符上对我来说毫无意义。:/
Noldorin

16
@Noldorin char* foo, bar;是什么类型bar
mASOUD

10
C由丹尼斯·里奇(Dennis Ritchie)于1972年开发,并在1988年与布赖恩·克尼根(Brian Kernighan)出版了《 K&R-C编程语言》的第二版,该书被许多人视作C的事实上的标准。
Marius Lian

10

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

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

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

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


10

如果您不想跟踪数组中的字符串数并想遍历它们,只需在末尾添加NULL字符串即可:

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

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

我相信这仅在C ++中有效。在C语言中,不能保证NULL为零,因此循环可能不会在应有的时候中断。如果我错了,请纠正我。
Palec

2
不知道:)如果愿意,可以在while语句中与NULL比较。
谢尔盖(Sergey)

9

字符串文字是 const char * s。

而且您对括号的使用很奇怪。你可能是说

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

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


3

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

char* a[size];

要么

char a[size1][size2];

代替。

参见Wikibooks中的数组指针


1
为您的不同方法而烦恼...像您这样的人会使堆栈溢出...
Sahu V Kumar

1

您好,您可以尝试以下方法:

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

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

在这里试试!


1
您能解释一下为什么需要变量j的for循环,即for(j = 0; j <1; j ++)吗?
SouvikMaji

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拾取指向数组字符串的指针,计数使用_countof函数拾取字符串数量。(相似sizeof(arr) / sizeof(arr[0]))。

另外,还有使用A2T宏将Ansi转换为unicode的方法,但这对于您的情况可能是可选的。


-6

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

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

真的就是这么简单。


4
您缺少;,这如何创建字符串数组?
键控
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.