340

I am trying to create an array of strings in C. If I use this code:

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

gcc gives me "warning: assignment from incompatible pointer type". What is the correct way to do this?

edit: I am curious why this should give a compiler warning since if I do printf(a[1]);, it correctly prints "hmm".

  • 14
    Just for the record, `char (*a[2])[14]` is an array of two pointers to an array of 14 chars. – avakar Jul 06 '09 at 19:05
  • 5
    I thought it was fourteen pointers to arrays of two chars xD – fortran Jul 06 '09 at 20:18
  • 123
    Most useful advice I ever read for deciphering C types: "Start at the name, read right when you can, left when you must": `char (*a[2])[14]` - start at `a`, move right: "array of two", move left: "pointer to", bracket complete so read right: "array of forteen", read left: "char"... Put it together and we have "a is array of two pointers to arrays of forteen chars" – Mark K Cowan Feb 07 '15 at 16:09
  • 5
    @dotancohen: That tip is what finally convinced me to write pointers as `char *str` rather than `char* str`. Coming from a Delphi/Pascal background, I was very accustomed to the latter way until I came across more complex types. The former way still looks ugly to me, but makes type notation more consistent (IMO). – Mark K Cowan Apr 14 '15 at 06:05

15 Answers15

295

If you don't want to change the strings, then you could simply do

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

When you do it like this you will allocate an array of two pointers to const char. These pointers will then be set to the addresses of the static strings "blah" and "hmm".

If you do want to be able to change the actual string content, the you have to do something like

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

This will allocate two consecutive arrays of 14 chars each, after which the content of the static strings will be copied into them.

Mikael Auno
  • 8,990
  • 2
  • 21
  • 16
242

There are several ways to create an array of strings in C. If all the strings are going to be the same length (or at least have the same maximum length), you simply declare a 2-d array of char and assign as necessary:

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

You can add a list of initializers as well:

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.

Instead of using a 2-d array of char, you can store a 1-d array of pointers to char:

char *strs[NUMBER_OF_STRINGS];

Note that in this case, you've only allocated memory to hold the pointers to the strings; the memory for the strings themselves must be allocated elsewhere (either as static arrays or by using malloc() or calloc()). You can use the initializer list like the earlier example:

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

Instead of copying the contents of the string constants, you're simply storing the pointers to them. Note that string constants may not be writable; you can reassign the pointer, like so:

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

But you may not be able to change the string's contents; i.e.,

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

may not be allowed.

You can use malloc() to dynamically allocate the buffer for each string and copy to that buffer:

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

BTW,

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

Declares a as a 2-element array of pointers to 14-element arrays of char.

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 3
    @Slater: yes, if it's the result of a `malloc` call. – John Bode Sep 07 '12 at 13:00
  • 1
    Why can we only use strcpy on String arrays declared as a 2D array. Why does standard assignment fail? – Andrew S Feb 07 '14 at 04:20
  • 5
    @AndrewS: The complete answer won't fit into a comment, but basically it's an artifact of how C treats array expressions; under most circumstances, an expression of type `T [N]` is converted to an expression of type `T *`, and the value of the expression is the address of the first element. So if you wrote `str = "foo"`, you'd be trying to assign the address of the first character of `"foo"` to the array `str`, which doesn't work. See [this answer](http://stackoverflow.com/questions/21391685/returning-a-two-dimensional-array-in-c/21393651#21393651) for more details. – John Bode Feb 07 '14 at 15:33
  • @JohnBode could you please add the small tweak? `char *strs[NUMBER_OF_STRINGS] = {0};` This helps prevent future problems by initializing `strs` to `NULL`. A lot of people read this post when the do google searches on array of strings in C. – cokedude Sep 08 '15 at 00:17
  • 1
    `char strs[NUMBER_OF_STRINGS][STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};` could be changed to `char strs[NUMBER_OF_STRINGS][MAX_STRING_LENGTH+1] = {"foo", "bar", "bletch", ...};` for clarity. – 71GA Feb 03 '20 at 07:01
120

Ack! Constant strings:

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

If I remember correctly.

Oh, and you want to use strcpy for assignment, not the = operator. strcpy_s is safer, but it's neither in C89 nor in C99 standards.

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

Update: Thomas says strlcpy is the way to go. [not portable]

mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • Is that C99? I don't believe it's possible in ANSI C. – Noldorin Jul 06 '09 at 18:51
  • Oh... maybe I'm mistaken; not sure what version it is. – mpen Jul 06 '09 at 18:56
  • 6
    It's possible in both C89 and C99. It also doesn't matter whether it's with const or without it, although the former is preferred. – avakar Jul 06 '09 at 19:01
  • 1
    Well, const is new, and you used to have to specify the size of the outer array (3 in this case), but otherwise this is perfectly acceptable K&R C. I have an old C book copyrighted 1984 that has a section showing how to do this. They call it a "ragged array". Of course it had no "operators", and strcpy_s is a new one on me. – T.E.D. Jul 06 '09 at 20:02
  • I think it prevents buffer overflows. I just remember my compiler complaining about it and told me to use that instead. – mpen Jul 07 '09 at 00:41
  • 7
    strcpy_s is a Microsoft function. It should probably be avoided because it is not in standard C. – Cromulent Jul 07 '09 at 04:26
  • 5
    strcpy_s and other "safe functions" are standardized as ISO/IEC TR 24731 (it's an ISO published standard and as such isn't available online for free; the most recent draft is http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf) – Pavel Minaev Jul 07 '09 at 21:44
  • 1
    Actually, the proper way to copy zero-terminated C strings is to use `strlcpy` unless you are 100% sure you don't need to. – Thomas Tempelmann Dec 19 '16 at 13:18
  • thank you for your explanation. its finally made the penny drop! bloody non settling pennies! – Jaspal Singh Rathour Mar 30 '21 at 12:39
  • This type of declaration is the one my Arduino IDE would accept. It would bail on Mikaels version which to me looks perfectly valid as well. – charlie Jul 29 '21 at 07:33
  • @ThomasTempelmann ... sure, if you don't want portable code. Which kind of defeats the purpose of C! So no the proper way to copy string is NOT `strlcpy`. Not until it's standardised. And then it's assuming it's in the standard you're using or the system you're using. – Pryftan Jun 15 '23 at 11:06
  • @mpen your update saying that `strlcpy()` is the way to go makes your answer non-portable. It's not the way to go. – Pryftan Jun 15 '23 at 11:09
  • @PavelMinaev whatever you've read it's not even in fedora so I'd say it's safe to say you should still avoid it if you want to be portable. – Pryftan Jun 15 '23 at 11:11
20

Here are some of your options:

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

The advantage of a2 is that you can then do the following with string literals

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

And for a3 you may do the following:

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

For a1 you will have to use strcpy() (better yet strncpy()) even when assigning string literals. The reason is that a2, and a3 are arrays of pointers and you can make their elements (i.e. pointers) point to any storage, whereas a1 is an array of 'array of chars' and so each element is an array that "owns" its own storage (which means it gets destroyed when it goes out of scope) - you can only copy stuff into its storage.

This also brings us to the disadvantage of using a2 and a3 - since they point to static storage (where string literals are stored) the contents of which cannot be reliably changed (viz. undefined behavior), if you want to assign non-string literals to the elements of a2 or a3 - you will first have to dynamically allocate enough memory and then have their elements point to this memory, and then copy the characters into it - and then you have to be sure to deallocate the memory when done.

Bah - I miss C++ already ;)

p.s. Let me know if you need examples.

Murphy
  • 3,827
  • 4
  • 21
  • 35
Faisal Vali
  • 32,723
  • 8
  • 42
  • 45
  • I needed string arrays for an Arduino project. At the end I used the a2 style. I initially tried the a1 style defining my string array as char a1[][2] = { "F3", "G3" ...etc. } as it was intended to store 2-character long strings. This gave unexpected output because I forgot the null-terminator would mean each string should have a size of at least 3 to store the 2 characters. Using the a2 style, I didn't need to specify the length of the string, and it could accommodate varying string lengths as well so I have decided to stick with that :-) – Jeromy Adofo Nov 18 '19 at 18:11
  • char (*a3[])[] = { &"blah", &"hmm" }; => does not work in g++ Apple LLVM version 9.1.0, but it works in gcc – 1234 Dec 23 '19 at 00:51
15

If you don't want to keep track of number of strings in array and want to iterate over them, just add NULL string in the end:

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

int i=0;
while(strings[i]) {
  printf("%s\n", strings[i]);
  //do something
  i++;
};
Sergey
  • 344
  • 2
  • 12
  • I believe this is valid only in C++. In C, NULL is not guaranteed to be zero, therefore the loop may not break when it should. Correct me if I am wrong. – Palec Apr 06 '17 at 19:04
  • 3
    No idea :) You may compare with NULL in while statement if you like. – Sergey Apr 10 '17 at 03:40
14

Or you can declare a struct type, that contains a character arry(1 string), them create an array of the structs and thus a multi-element array

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 
 }

One of the advantages of this over any other method is that this allows you to scan directly into the string without having to use strcpy;

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
FutureSci
  • 1,750
  • 1
  • 19
  • 27
12

If the strings are static, you're best off with:

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

While not part of basic ANSI C, chances are your environment supports the syntax. These strings are immutable (read-only), and thus in many environments use less overhead than dynamically building a string array.

For example in small micro-controller projects, this syntax uses program memory rather than (usually) more precious ram memory. AVR-C is an example environment supporting this syntax, but so do most of the other ones.

Bryce
  • 8,313
  • 6
  • 55
  • 73
11

In ANSI C:

char* strings[3];
strings[0] = "foo";
strings[1] = "bar";
strings[2] = "baz";
Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 8
    @Zifre: I wholly disagree. It very much is part of the type - a "char pointer" in this case. What would you say anyway... it's part of the variable name? I have seen many a competent programmer use this style. – Noldorin Jul 06 '09 at 19:56
  • In fact, if you know C#, you should be aware that Microsoft agrees with this, and explicitly *disallows* putting the star after the space. – Noldorin Jul 06 '09 at 19:59
  • To add another point: it can never be confused with the dereference operator as well. Convinced yet? Well, probably not, but I've made my argument. – Noldorin Jul 06 '09 at 20:00
  • 14
    Just for anyone else reading this, I would like to point out that Bjarne Stroustrup puts the * by the type... – MirroredFate Mar 29 '13 at 18:40
  • 1
    @MirroredFate: Correct. Indeed, it's recommended practice in C++ from what I know. Semantically it makes no sense to me to put it by the identifier, because of the way it's used. :/ – Noldorin Mar 29 '13 at 19:47
  • There's different ways of looking at it, are we saying for "`char * a`" that "`a is a char*`" or are we saying that "`*a is a char`"? For more complex types, the second way of thinking becomes pretty much mandatory (see my comment on the question post) – Mark K Cowan Apr 14 '15 at 06:00
  • @Zifre it actually doesn't matter one way or another. both compile, and numerous standards conflict on this issue. you could even do `char * strings[3];` which is also "correct" – Mike Bell May 16 '15 at 02:08
  • 16
    @Noldorin `char* foo, bar;` what is the type of `bar`? – mASOUD Nov 03 '15 at 17:37
  • 10
    C was developed by Dennis Ritchie in 1972 and in 1988 he and Brian Kernighan published the second edition of K&R - The C Programming Language, a book many holds as de facto standard for C. They put the * by the identifier. – Marius Lian Feb 22 '16 at 07:21
  • @Noldorin You mean the same company that uses the unreadable Hungarian notation? Why would you ever take style advice from them? – MarcusJ Apr 06 '18 at 07:15
  • @MikeBell Because they designed the language I mentioned (C#)? – Noldorin Apr 06 '18 at 14:32
  • 1
    I love your philosophical question @mASOUD. I tried it on my Arduino IDE (basically a slightly modified C++ compiler) and what worked was `char* foo="best", *bar="friend";` or better still, `char *foo="best", *bar="friend";`. That is, without the `*` in front of `bar`, it is treated as a normal character not a character pointer. – Jeromy Adofo Nov 18 '19 at 18:43
9

The string literals are const char *s.

And your use of parenthesis is odd. You probably mean

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

which declares an array of two pointers to constant characters, and initializes them to point at two hardcoded string constants.

dmckee --- ex-moderator kitten
  • 98,632
  • 24
  • 142
  • 234
3

Your code is creating an array of function pointers. Try

char* a[size];

or

char a[size1][size2];

instead.

See wikibooks to arrays and pointers

Dario
  • 48,658
  • 8
  • 97
  • 130
1

hello you can try this bellow :

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

a nice example of using, array of strings in c if you want it

#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;
}
Aominé
  • 472
  • 3
  • 11
1

Each element is a pointer to its first character

const char *a[2] = {"blah", "hmm"};
ashkanyo
  • 81
  • 6
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");
}

Here try this!!!

admdrew
  • 3,790
  • 4
  • 27
  • 39
Aditya
  • 1
  • 1
0

I was missing somehow more dynamic array of strings, where amount of strings could be varied depending on run-time selection, but otherwise strings should be fixed.

I've ended up of coding code snippet like this:

#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 picks up pointer to array strings, and count picks up amount of strings using _countof function. (Similar to sizeof(arr) / sizeof(arr[0])).

And there is extra Ansi to unicode conversion using A2T macro, but that might be optional for your case.

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
-8

A good way is to define a string your self.

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

It's really that simple.

IceCodr
  • 17