1

I need to hold an array of C strings. Now I know C strings are just an array of chars so essentially what I want is a 2d array of chars. The strings I'm trying to store will also never exceed 6 characters. My plan is to initialize a char array with 50 "string slots" and then if I hit 50 strings reallocate the array's memory to double it's capacity. I've tried something simple like:

int main() {
    char strings[50][6];
    strings[0] = "test";
    printf("The string is: %s", strings[0]);
    return(0);
}

But, when I go to compile it I get the following error:

test.c: In function ‘main’: test.c:3: error: incompatible types when assigning to type ‘char[6]’ from type ‘char *’ test.c:4: warning: incompatible implicit declaration of built-in function ‘printf’

Can anyone point in me in the right direction?

3
  • "never exceed 6 characters." -> you need space for 7 bytes (terminating '\0') Commented Sep 16, 2010 at 21:02
  • declaring 'strings' inside of main() is going to use a lot of stack space, better to allocate from heap (malloc) or declare outside of the function. Commented Sep 16, 2010 at 21:17
  • 1
    @Casey, it uses 300 bytes. A typical stack size is much larger. Commented Sep 16, 2010 at 21:55

6 Answers 6

5

strncpy(strings[0], "test", 6); unless your C library has strlcpy(). However if you are going to need to vary the size of the storage, you're better off using a char ** with malloc(), realloc() and free().

Sign up to request clarification or add additional context in comments.

4 Comments

+1 for the malloc suggestion as you can't realloc statically declared char arrays very easily.
strncpy(strings[0], "testTest", 6); is going to leave you with unterminated string, so actually the safest way to do this is: snprintf(strings[0], sizeof(strings[0]), "%s", "whatever string you wish");
Careful, if string is 6 characters, then strncpy will not NULL terminate the string.
Or alternatively, strings[0][0] = '\0'; strncat(strings[0], "test", 6 - 1); (strncat does always nul-terminate the destination).
2

One can't assign arrays directly in that way. In your current case, you would need to do something like...

strcpy (strings[0], "test");

It would be more idiomatic to use an array of pointers, though. Have a look at p111 and onwards of K & R.

12 Comments

Sadly you're only allowed to flag answers for being spam or offensive, not for containing a recommendation to use strcpy().
@Graham Lee: That's what downvoting is for. @Brian Hooper: -1 for recommending strcpy.
@Graham Lee, Platinum Azure, I agree, you would be quite correct if the string in question were user input. But it isn't, in this case. One could put strncpy (string[0], "test", 6) as suggested above, but that just adds redundancy to the problem, as "test" isn't six characters long; perhaps strncpy (string[0], "test", strlen ("test")) might be an improvement. What do you think?
@Brian Hooper: Also, regarding your scenario about using 6 vs strlen("test"): As it turns out the former is faster, because strncpy will keep copying either until it hits 6 characters OR until the null terminator, whichever comes first. strlen needs to calculate the length on the other hand, so you iterate twice. Using strlen("test") is no good if you have buffer overflow conditions, because it will still copy all of a potentially malicious variable in those conditions. You need to use the maximum length of your destination as your upper bound, not the length of your source.
This is nonsense. If you are calling strcpy without knowing the length of the source string, then that is your problem. I have found very few cases where it is okay to truncate the source string while copying "just to be safe". As a programmer, it is your responsibility to make sure that destination is big enough. And strncpy is broken anyway.
|
1

Use strncpy (if at all possible) or strcpy for your assignment.

Comments

1

First the easy part. You do need to

#include <stdio.h>

to get rid of the incompatible printf warning. This has to do with the way the standard says C works, which is to allow you to make some function that is unlike the standard printf, the implicit declaration of that function with its signature (incorrectly) guessed by the compiler, and the compiler knowing that while you can define a different printf you probably didn't actually mean to.

Ok, now the more complicated part. Arrays in C are a little special. The can evaluate to pointer literals (which can't be assigned to, which is similar to trying to 6 = 4;), or they can evaluate to an entire array, depending on context. Usually they are pointer literals, but in this case strings[0] is seen as an array, which is why you get the error you got rather than one stating that strings[0] was an invalid l-value (left-value, meaning something that can be on the left side of a =). Either way you can't copy a character pointer literal (which is what "test" evaluates to) to an array. When you do this on the line where you declare a string (char array) the compiler treats it differently, though, which can cause some confusion. Anyway, you need to either use strcpy to copy the characters that make up "test" or initialize strings[0] to "test" like this:

char strings[50][6] = { "test" };  // only initializes the first member of the array

Comments

1

You can't assign array contents using the = operator. First of all, an array object cannot be a target of the assignment operator (Online C Standard, draft n1256, section 6.5.16.1, paragraph 1). strings[0] is an array object of type char [6], so it can't appear on the LHS of the = operator.

Second of all, when an array expression is not an operand of either the sizeof or address-of & operators and is not a string literal being used to initialize the contents of another array, the type of the expression is implicitly converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array (section 6.3.2.1, paragraph 3).

The string literal "test" is a 5-element array of char (const char in C++) with static extent (meaning the memory for it is allocated at program startup and held until the program exits). However, when it appears in the expression

strings[0] = "test";

its type is converted from "5-element array of char" to "pointer to char" and its value is the address of the first element, so what you wind up doing is attempting to assign a pointer value to an array object, which is not a compatible type; bad juju, over and above not being able to assign an array object anyway.

If you want to copy the contents of one array to another, then you will need to either assign each array element individually, such as

strings[0][0] = 't';
strings[0][1] = 'e';
strings[0][2] = 's';
strings[0][3] = 't';
strings[0][4] = 0;

or even

size_t len = strlen("test");
size_t i;
for (i = 0; i < sizeof strings[0] - 1 && i < len; i++)
  strings[0][i] = "test"[i]; // yes, you can subscript a string literal
strings[0][i] = 0;

or use a library function like memcpy(), strcpy(), strncpy(), strcat(), sprintf(), etc.:

strcpy(strings[0], "test");

or

strncpy(strings[0], "test", sizeof strings[0] - 1); // -1 to leave room
                                                    // for 0 terminator
                                                    // if necessary  

or

sprintf(strings[0], "%*s", (int) sizeof strings[0] - 1, "test");

Note that you can initialize the array's contents when you declare it, like so:

char foo[] = "test";      // foo is implicitly sized to 5 (+1 for 0 terminator)
int  bar[] = {1,2,3,4,5}; // again, size is implied from initializer

float f[3] = {1.0, 2.0, 3.0}; // Initializer cannot contain more items than 
                              // array is sized for

I see there's a merry war over the use of strcpy() vs. strncpy() in the comments to another answer; my position is to use whichever one is appropriate to the given situation. If you know that your buffers are big enough to handle the largest possible input, use strcpy(). If not, use strncpy(), but be aware that you may have to add the 0 terminator manually.

Comments

0

The problem you have is in the way that the compiler interprets the statement char strings[50][6];

Instead of what you hoped, a char array with 50 slots for 6 char strings, you got a char array of single chars with dimesions 50x6.

Rather than char strings[50][6];, the way you want to initialise your array is as follows (I only know how to do this on the heap, sorry):

char ** strings[50] = malloc(50 * sizeof(char *));
for(int i = 0; i < 50; ++i)
{
    strings[i] = malloc(50 * 6 * sizeof(char *));
}

Don't forget to clean with frees afterwards.

EDIT: And as said above. Before your main method. Inlcude the line #include <stdio.h>. This is where the printf() function is located.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.