Arrays of strings in C - c

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?

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().

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.

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

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

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.

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.

Related

Why doesn't the C double asterisk work for creating a 2D array?

Why does this work:
char *name = "steven";
but this doesn't:
char **names = {"steven", "randy", "ben"};
Or, why does this work:
char *names[] = {"steven", "randy", "ben"};
but, again, this doesn't:
char **names = {"steven", "randy", "ben"};
A char **p is not a 2D array, it is a pointer to a pointer to a character. However, you can have more pointers and more characters following, resembling a kind of model of a 2D structure of characters.
C compiler interpret { "steven" } as a 1D array of characters, because the braces are optional (standard chapter 6.7.9 paragraph 14).
As you tried, you can declare an array of pointers to a character by char *p[].
But if you want to have that pointer (to pointers to characters), you need to tell your compiler. The address of an array can be assigned to the pointer.
char **p = (char *[]){ "steven", "randy", "ben", };
Additional note: Since string literals are unmutable, you better add a const for the characters. And since the address of these unnamed string literals are constant, too, you can provide another one.
const char * const *p = (const char * const []){ "steven", "randy", "ben", };
I also wondered, what if I could answer you in the simplest way possible.
Why are you confused?
A simple pointer to integer for example allocated with 8 cells, acts in the same way as an array has a dimension of 8 cells.
The only difference, that you can't see, is that a pointer that has 8 cells allocated is on a part of the memory that is called the HEAP, while a variable of type int tab[8] is allocated on the STACK.
Indeed, since the cells are linked in memory, it is easy to imagine that a pointer and an array whose first cell address is sent are the same thing.
Why it doesn't work in the other case
However, when the idea comes to associate (** and [][])
Let's take the example of an int ** ;
int **tab;
tab = malloc(sizeof(int *) * 4);
//secure malloc do not forget
for (int i = 0; i < 4; i++)
{
tab[i] = malloc(sizeof(int) * 3);
//secure malloc do not forget
}
and an
int[4][3];
You have a problem.
To imagine, a double array type follows itself in memory, because it is the very principle of arrays.
While a double pointer has first 4 cells of type int * allocated (which follow each other in memory) and then each pointer of these 4 cells, each points to a memory area of 3 ints which follow each other. But the whole thing does not follow each other in the memory!
A way that may interest you
One thing you can do instead is to create an int ptr(*)[3];
which can point to the first element of an array of size 3, i.e. the address of an array [4][3] for example.
The initializer for a scalar object may not contain more than one item.
6.7.9 Initialization
...
Constraints
2 No initializer shall attempt to provide a value for an object not contained within the entity
being initialized.
...
11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The
initial value of the object is that of the expression (after conversion); the same type
constraints and conversions as for simple assignment apply, taking the type of the scalar
to be the unqualified version of its declared type
C 2011 Online Draft
char **names declares a single, scalar object, not an array, so any initializer for it must only contain a single item. That initializer may be a single string ("steven"), optionally enclosed in braces ({ "steven" }). However, it may not be a list of initializers.

Array of Pointers in C how is the operator [ ] used

Hello I am new to C and its pointers. I thought I understood pointers untill I stumbled upon Array of Pointers.
Why is the output of these two code fragements exactly the same. I would expect that my normal array gives me the values. And the array that holds of pointers gives me the addresse of the values.
char *array[] = {'a','b','c','d'};
for(int i=0; i<4; i++){
printf("%c\n", array[i]);
}
char array[] = {'a','b','c','d'};
for(int i=0; i<4; i++){
printf("%c\n", array[i]);
}
I know that '[]' is used to dereference and get the value of the adress the pointer is pointing at but it is also used to access array elements and the only reasonable explanation here is that it does both at the same time. Is this how I should think about it?
In the first code snippet, you are initializing an array of pointers with character constants. This results in an integer-to-pointer conversion of those constants. So for example the first element of the array contains the address 97 (assuming ASCII encoding).
When you later attempt to print, you are passing a char * where a char is expected. Using the wrong format specifier triggers undefined behavior. One of the ways that UB can manifest is that things appear to work properly which is the case here.
What probably happened is that pointers and integers get passed to functions in the same manner. And if your system uses little-endian byte representation (which it appears it does), it will end up reading the value used to initialize the array.
Regarding the array index operator [], the expression E1[E2] is exactly the same as *((E1) + (E2)). In the first code snippet array[i] has type char * while in the second code snippet it has type char because that is the type of the respective array elements.
Like already explained by dbush, your first example is wrong.
A more practical use case to demonstrate the pointer part with a string:
#include <stdio.h>
int main(int argc, char** argv) {
char *str = "abc"; //string literal - constant!
printf("%p address of str[0] - str[0] = %c \n", str, *str);
printf("%p address of str[1] - str[1] = %c \n", str+1, *(str+1));
printf("%p addredd of str[2] - str[2] = %c \n", &str[2], str[2]); //alternative notation
return 0;
}
Also there are several similarities between arrays and pointers, for the string example
you can not change the string (the string literal is constant), but you can change the pointer to another string. Other with an array, where you can change the content, but you can not iterate over the array with ++arr, like you can do with the pointer notation, nor can you change the address of arr. Another fact, the array name is the address of the array. And yeah its the same address as the first array element.
With time you will find several useful cases for arrays of pointers, because you already
know, that switching the pointer (the adresses of the object the pointer points to) often provide a more performant method than using the objects themselves...
I would expect that my normal array gives me the values. And the array that holds of pointers gives me the addresse of the values.
You put the same data into each array, so it's not surprising that you got the same data out of them. Specifically:
char *array[] = {'a','b','c','d'};
In this case, you created an array containing four values, and you told the compiler that those values are of type char *. But whatever their type, they're still the same values, 'a', 'b', and so on. You might as well have written:
char *array[] = {97, 98, 99, 100);
because that's exactly the same thing. Specifying the type of the contents of the array as char * doesn't make the compiler treat the values in the array differently -- it doesn't say "oh, I guess in this case I should take the addresses of those values instead of using the values themselves" just because the type is char *. If you want an array of pointers to some set of values, you'll need to get those pointers yourself using other means, such as the & operator, allocating space for each one, etc.
Note: In a comment below, M.M. points out that using values of type char to initialize an array of type char * isn't allowed by the C standard. In my experience, compilers typically warn about this kind of thing (you should've gotten several warnings like warning: incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int' when you compiled your code), but they'll still soldier on and compile the code. In summary: 1) Don't do that, and 2) different compilers may do different things in this situation.
I know that '[]' is used to dereference and get the value of the address the pointer is pointing at but it is also used to access array elements and the only reasonable explanation here is that it does both at the same time.
An array in C is a single contiguous piece of memory in which a number of values, all of the same type and size, are arranged one after another. The [] operator accesses individual values within the array by calculating an offset from the array's base address and using that to get the value. I think the thing that's confusing in your example is that you've created an array of char *, but with values that look like char. As far as the compiler is concerned, though, 'a' (a.k.a. 97, a.k.a. 0x61) is an acceptable value for a pointer to a character, and you could dereference that and get whatever character is stored at location 0x61. (In reality, doing that might cause an exception; the lowest region of memory is reserved on many machines.)
I know that [] is used to dereference and get the value of the adress the pointer is pointing at but it is also used to access array elements and the only reasonable explanation here is that it does both at the same time. Is this how I should think about it?
No. [] is used (in the place you use it) to indicate an array in which the initializer will state the number of elements the array has. Derreferencing a pointer is done with the * left unary operator.
The expression
char *array[] = ...
is used to declare an array of pointers to chars, that will be initialized (normally) with a list of string literals, like these:
char *array[] = { "First string", "Second string", "third string" };
and
char array[] = { 'a', 'b', 'c', 'd' };
making use of the information given above, declares an array of characters with space for four characters, and initialized with array[0] = 'a', array[1] = 'b', array[2] = 'c', array[3] = 'd'.
So the first example will give you an error when trying to initialize an array cell (of pointer to char type) with an integer value (a char is a type of integer) and the second example will compile and execute fine.
The reason you get the same output in both case is unknown(Undefined Behaviour) (well I have some idea) because you have assigned to a pointer variable an integer value (this is probably the thing as the value stored is small enough that can be reinterpreted back without losing information) but the thing is that you have stored the same thing in the array cells, so why do you ask why the output is the same..... what did you expect? You store a char value in a pointer variable and then get it back and print in both samples with exactly the same format specifier, why do you expect (except for conversion errors back to an integer) both codes printing different things? (well, it's undefined behaviour, so you can expect anything and the computer can do otherwise)
There are two compiler warnings you elegantly skip:
warning: initialization of 'char *' from 'int' makes pointer from
integer without a cast [-Wint-conversion]
6 | char *array[] = {'a','b','c','d'};
| ^~~
And the second warning:
warning: format '%c' expects argument of type 'int', but argument 2
has type 'char *' [-Wformat=]
8 | printf("%c\n", array[i]);
| ~^ ~~~~~~~~
| | |
| int char *
| %s
The suggested %s of course would not help. To get valid char-pointers into array[] it would take a "..." string literal, a malloc or a & adress-of on char variable.

Array syntax and pointers in C

Is my understanding of arrays in C correct?
Arrays are nothing more than a syntactic convenience such that, for instance, when you declare in your C code an array:
type my_array[x];
the compiler sees it as something equivalent to:
type *my_array = malloc(sizeof(*my_array) * x);
with a free system call that releases my_array once we leave the scope of my_array.
Once my_array is declared
my_array[y];
is nothing more but:
*(my_array + y)
Transposing this to character strings; I was also wondering what was happening behind the curtain with
char *my_string = "Hello"
and
my_string = "Hello"
No, an array object is an array object. C has some odd rules that make it appear that arrays and pointers are the same thing, or at least very similar, but they very definitely are not.
This declaration:
int my_array[100];
creates an array object; the object's size is 100 * sizeof (int). It does not create a pointer object.
There is no malloc(), even implicitly. Storage for my_array is allocated the same way as storage for any object declared in the same scope.
What may be confusing you is that, in most but not all contexts, an expression of array type is implicitly converted to a pointer to the array's first element. (This gives you a pointer value; there's still no pointer object.) This conversion doesn't happen if the array expression is the operand of a unary & or sizeof. &my_array gives you the address of the array, not of some nonexistent pointer obejct. sizeof my_array is the size of the entire array (100 * sizeof (int)`), not the size of a pointer.
Also, if you define a function parameter with an array type:
void func(int param[]) { ... }
it's adjusted at compile time to a pointer:
void func(int *param) { ... }
This isn't a conversion; in that context (and only in that context), int param[] really means int *param.
Also, array indexing:
my_array[3] = 42;
is defined in terms of pointer arithmetic -- which means that the prefix my_array has to be converted to a pointer before you can index into it.
The most important thing to remember is this: Arrays are not pointer. Pointers are not arrays.
Section 6 of the comp.lang.c FAQ explains all this very well.
Once my_array is declared
my_array[y];
is nothing more but :
*(my_array + y)
Yes, because my_array is converted to a pointer, and the [] operator is defined so that x[y] means *(x+y).
Transposing this to character strings; i was also wondering what was
happening behind the curtain with
char *my_string = "Hello"
and
my_string = "Hello"
"Hello" is a string literal. It's an expression of type char[6], referring to an anonymous statically allocated array object. If it appears on the RHS of an assignment or initializer, it's converted, like any array expression, to a pointer. The first line initializes my_string so it points to the first character of "Hello". The second is a pointer assignment that does the same thing.
So what about this?
char str[] = "Hello";
This is the third context in which array-to-pointer conversion doesn't happen. str takes its size from the size of the string literal, and the array is copied to str. It's the same as:
char str[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
No!
type array[n] is a variable stored on stack
type *array is a pointer variable stored on the stack too. But after array = malloc(sizeof(*array) * n); it'll point to some data on the heap
If it walks like a duck, swims like a duck and flies like a duck, then it is a duck.
So, let's see. Arrays and pointers have some common attributes as you correctly described, however, you can see there are some differences. Read more here.

How to properly initialize a string

How would I go about defining the following string for the following function?
As of now I get the warning:
C4047: '=' : 'const char' differs in levels of indirection from 'char [4]'
and the error:
C2166: l-value specifies const object.
Both in the third line of the code below:
uint8_t *buffer= (uint8_t *) malloc(sizeof(uint32_t));
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
newval = protobuf_writeString (buffer, stringaling);
uint32_t protobuf_writeString(uint8_t *out,const char * str)
{
if (str == NULL)
{
out[0] = 0;
return 1;
}
else
{
size_t len = strlen (str);
size_t rv = uint32_pack (len, out);
memcpy (out + rv, str, len);
return rv + len;
}
}
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
This is not valid code. You are trying to assign to a const variable, which is illegal. Then you are trying to assign an array of characters to a character. And finally, even if you had a non-const array of characters of the right size, you still can't assign arrays, because they're not first-class values.
Try using
char *stringaling = malloc(sizeof(uint32_t));
strcpy(stringaling, "fun");
...instead, and see if that doesn't work better. Note, however, that it's pretty much accidental that (at least usually) sizeof(uint32_t) happens to be the right size to hold "fun". You normally don't want to do that.
Alternatively, you may want:
char const *stringaling = "fun";
or:
char stringaling[] = "fun";
The assignment you had won't work though -- C has only the very most minimal support for strings built into the language; most operations (including copying a string) are normally done via library functions such as strcpy.
"fun" is a string literal, which is essentially a const char *.
stringaling is also a const char *, so your third line is trying to assign a const char * to a const char, which is not going to fly.
If it's a constant string, you can just do this:
const char *stringaling = "fun";
If your input string is dynamic, you can do this:
char *stringaling= (char *) malloc(strlen(inputString)+1);
strcpy(stringaling, inputString);
Obviously, if you malloc it, you need to free it, or feel the wrath of a memory leak.
If you really want to initialize the char *, you could write this instead:
const char *stringaling = "fun";
And here's some reference.
without all the stuff you can also use:
newval = protobuf_writeString (buffer, "fun" );
First problem:
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
Several problems on this line.
First of all, you don't want to declare stringaling as const char *; you will not be able to modify whatever stringaling points to (IOW, *stringaling will not be writable). This matters since you want to copy the contents of another string to the location pointed to by stringaling. Drop the const keyword.
Secondly, malloc(sizeof(uint32_t)) just happens to allocate enough bytes (4) for this particular string, but it's not clear that you meant to allocate 4 bytes. When allocating memory for an array (and strings are arrays), explicitly indicate the number of elements you intend to allocate.
Finally, casting the result of malloc is considered bad practice in C. The cast will suppress a useful diagnostic message if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope. As of the 1989 standard, malloc returns void *, which can be assigned to any other object pointer type without needing to cast. This isn't true in C++, so a cast is required there, but if you're writing C++ you should be using new instead of malloc anyway.
So, change that line to read
char *stringaling = malloc(LEN); // or malloc(LEN * sizeof *stringaling), but
// in this case that's redundant since
// sizeof (char) == 1
where LEN is the number of chars you want to allocate.
The general form for a malloc call is
T *p = malloc (N * sizeof *p);
where T is the base type (int, char, float, struct ..., etc.), and N is the number of elements of type T you want to allocate. Since the type of the expression *p is T, sizeof *p == sizeof(T); if you ever change the type of p, you don't have to replicate that change in the malloc call itself.
Second problem:
*stringaling = "fun";
Again, there are several issues at play. First, you cannot assign string values using the = operator. String literals are array expressions, and in most contexts array expressions have their type implicitly converted ("decay") from "N-element array of T" to "pointer to T". Instead of copying the contents of the string literal, you would be simply assigning a pointer to the first character in the string.
Which would "work" (see below), except that you're dereferencing stringaling in the assignment; the type of the expression *stringaling is const char (char after making the change I indicated above), which is not compatible for assignment with type char *. If you drop the dereference operator and write
stringaling = "fun";
you'd fix the compile-time error, but now you have another problem; as mentioned above, you haven't copied the contents of the string literal "fun" to the memory block you allocated with malloc; instead, you've simply copied the address of the string literal to the variable stringaling. By doing so, you lose track of the dynamically-allocated block, causing a memory leak.
In order to copy the string contents from one place to another, you'll have to use a library function like strcpy or strncpy or memcpy, like so:
strcpy(stringaling, "fun");
If stringaling doesn't need to live on the heap (for example, you're only using it within a single function and deallocating it before returning), you could avoid memory management completely by declaring it as a regular array of char and initializing it with "fun":
char stringaling[] = "fun";
This is a special case of initializing an array in a declaration, not an assignment expression, so the = does copy the contents of the string literal to the stringaling array. This only works in an array declaration, however. You can later modify the array with other string values (up to 3 characters plus the 0 terminator), but you'd have to use strcpy again:
strcpy(stringaling, "one");
If you don't need to modify the contents of stringaling, you could just do
const char *stringaling = "fun";
This copies the address of the string literal "fun" to the variable stringaling. And since attempting to modify the contents of a string literal invokes undefined behavior, we do want to declare stringaling as const char * in this case; that will prevent you from accidentally modifying the string literal.

c string basics, why unassigned?

I am trying to learn the basics, I would think that declaring a char[] and assigning a string to it would work.
thanks
int size = 100;
char str[size];
str = "\x80\xbb\x00\xcd";
gives error "incompatible types in assignment". what's wrong?
thanks
You can use a string literal to initialize an array of char, but you can't assign an array of char (any more than you can assign any other array). OTOH, you can assign a pointer, so the following would be allowed:
char *str;
str = "\x80\xbb\x00\xcd";
This is actually one of the most difficult parts of learning a programming language.... str is an array, that is, a part of memory (size times a char, so size chars) that has been reserved and labeled as str. str[0] is the first character, str[1] the second... str[size-1] is the last one. str itself, without specifiying any character, is a pointer to the memory zone that was created when you did
char str[size]
As Jerry so clearly said, in C you can not initialize arrays that way. You need to copy from one array to other, so you can do something like this
strncpy(str, "\x80\xbb\x00\xcd", size); /* Copy up to size characters */
str[size-1]='\0'; /* Make sure that the string is null terminated for small values of size */
Summarizing: It's very important to make a difference between pointers, memory areas and array.
Good luck - I am pretty sure that in less time than you imagine you will be mastering these concepts :)
A char-array can be implicitely cast to a char* when used as Rvalue, but not when used as Lvalue - that's why the assignment won't work.
You cannot assign array contents using the =operator. That's just a fact of the C language design. You can initialize an array in the declaration, such as
char str[size] = "\x80\xbb\x00\xcd";
but that's a different operation from an assignment. And note that in this case, and extra '\0' will be added to the end of the string.
The "incompatible types" warning comes from how array expressions are treated by the language. First of all, string literals are stored as arrays of char with static extent (meaning they exist over the lifetime of the program). So the type of the string literal "\x80\xbb\x00\xcd" is "4 5-element array of char". However, in most circumstances, an expression of array type will implicitly be converted ("decay") from type "N-element array of T" to "pointer to T", and the value of the expression will be the address of the first element in the array. So, when you wrote the statement
str = "\x80\xbb\x00\xcd";
the type of the literal was implicitly converted from "4 5-element array of char" to "pointer to char", but the target of the assignment is type "100-element array of char", and the types are not compatible (above and beyond the fact that an array expression cannot be the target of the = operator).
To copy the contents of one array to another you would have to use a library function like memcpy, memmove, strcpy, etc. Also, for strcpy to function properly, the source string must be 0-terminated.
Edit per R's comment below, I've struck out the more dumbass sections of my answer.
To assign a String Literal to the str Array you can use a the String copy function strcpy.
char a[100] = "\x80\xbb\x00\xcd"; OR char a[] = "\x80\xbb\x00\xcd";
str is the name of an array. The name of an array is the address of the 0th element. Therefore, str is a pointer constant. You cannot change the value of a pointer constant, just like you cannot change a constant (you can't do 6 = 5, for example).

Resources