c string basics, why unassigned? - c

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

Related

Why can't multiple chars be assignable in an array?

Take the following example of trying to do character assignment to an array:
char newer_string[3][6];
newer_string[0] = "One";
newer_string[0] = "Two";
newer_string[0] = "Three";
This fails with the following error:
main.c:46:18: error: array type 'char [6]' is not assignable
Why is it necessary to add each individual one-at-a-time, for example"
char newer_string[3][6];
newer_string[0][0] = 'O';
newer_string[0][1] = 'n';
// ...etc...
What's the most common way to "append" items to an empty array?
Additionally, perhaps I'm misunderstanding the need for a 2D array (or what it even is), because I can also do something like:
char *newer_string[3];
newer_string[0] = "One";
newer_string[1] = "Two!!!";
newer_string[2] = "Three";
What would be the best way to assign multiple "words" to an array (a 2D character array? or 1D string-pointer array?)
Type Controls Everything
You cannot *assign" a string to an ARRAY. You can assign the address of a String-Literal to a pointer.
When you declare char newer_string[3][6]; you declare a 2D array of char (an array of 1D arrays). You can initialize the contents of an array at the time of declaration, but thereafter, you cannot assign the contents of the array. When you attempt to assign the address of the String-Literal "One" to an array, your compiler properly throws the error:
main.c:46:18: error: array type 'char [6]' is not assignable
(your compiler is correct, you are attempting to assign type char* to char[6])
Remember on access, except when used as the operand of sizeof or used to initialize an array, 6.3.2.1(p3) apples (see below) making a String-Literal type char* (which is a pointer to (the address of) the first character in the literal). A string-literal is immutable and any attempt to modify is Undefined C11 Standard - 6.4.5 String literals(p7), but a few non-conforming compilers provide for mutable string literals.
On access, your 2D array is converted to a pointer to the first 1D array. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) The type is char (*)[6] (pointer-to-array of char[6]). When you derefernce the pointer-to-array using the [..] operator, you are left with a simple array. You cannot assign the contents of an array.
To copy to the array, either use memcpy (or strcpy if a nul-terminated string is wanted), or loop over each index assigning each char.
Your Array of Pointers
With your edit, char *newer_string[3];, newer_string has type char *[3] (an array of pointers [3] -- e.g. an array of 3-pointers). You CAN assign the address of a String-Literal to a pointer. The types are compatible.
Look things over and let me know if you have further questions.

How can a char pointer contain a string in it?

If I define a char pointer in a C program and initialize it to "some String"
Can someone explain how a char pointer that's supposed to hold an address in it can hold a string in it?
Isn't it a contradiction to the definition of a pointer? What am I missing here?
For example :
char pointer=" how is it possible at all ? ";
printf("%s",pointer);
String literals, like "how is it possible at all ? " are really arrays of read-only characters stored somewhere by the compiler.
When you do
char *pointer=" how is it possible at all ? ";
you initialize pointer to point to the first element of that array.
This is very similar to
char string[] = " how is it possible at all ? ";
char *pointer = &string[0]; // Make pointer point to the first character in the array
How pointers themselves work depends on the compiler and the target architecture, but most of the time they are simple integers whose value is the address of the memory they point to. Then the compiler handles them specially and translates usage of the pointers into the correct machine-code instructions to access the memory a pointer is pointing to.
Because string literals are read only, that's the reason you should really use const char * when making pointers to them. C allows plain non-constant char *, but then the compiler might not be able to detect attempts to modify the read-only literal, which leads to undefined behavior.
In the statement:
char *pointer=" how is it possible at all ? ";
" how is it possible at all ? " is a string literal and a string literal is an array of characters.
From C Standards#6.3.2.1p3
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue.
So, the string literal which is an array decays into pointer of type char.
Can someone explain how a char pointer that's supposed to hold an address in it can hold a string in it?
Another way to look at it, by analogy: the same way a huge building can have a street address such as "123 Main Street".
The address is where it is - not how big it is.

Char not working in multi dimensional array in C. Need clarification

Im trying to create a 2d array for multiple data types but it seems to not be accepting the char data type. Why is this?
struct {
union {
int ival;
float fval;
char cval[50];
} val;
} as[120][4];
as[0][1].val.cval = "Testtttt"; ***This does not work***
as[1][1].val.ival = 3; ***This works***
You are in c, thus you should use string.h when it comes to string handling!
Change this:
as[0][1].val.cval = "Testtttt";
to this:
strcpy(as[0][1].val.cval, "Testtttt");
by using strcpy(), instead of the assignment operator (this would work in c++, not in c).
Of course, alternative functions exist, such as strncpy()* and memcpy().
Moreover, since C string handling seems new to you, you must read about null terminated strings in C.
*Credits to #fukanchik who reminded me that
In C, this code
as[0][1].val.cval
can not be assigned to. Per the C Standard, 6.3.2.1 Lvalues, arrays, and function designators:
Except when it is the operand of the sizeof operator, the _Alignof
operator, or the unary & operator, or is a string literal used to
initialize an array, an expression that has type "array of type"
is converted to an expression with type "pointer to type" that
points to the initial element of the array object and is not an
lvalue.
Without getting too in-depth into the C Standard, an lvalue is something you can assign something to. Thus, this code
as[1][1].val.ival
represents an lvalue and you can assign 3 to it.
The reason an array can't be assigned to is because it decays to "an expression with type ‘‘pointer to type". In other words, a bare array like
as[0][1].val.cval
is treated as the address of the array.
And the address of the array is where it is and is not something that can be assigned to.
Your val.cval members are arrays of char. String literals also represent arrays of char. C does not support whole-array assignment, regardless of the type of the array elements.
You can copy the contents of one array to another in various ways. strcpy() will do it for null-terminated arrays of char. memcpy() and / or memmove() will do it more generally, and of course you can always write an element-by-element copy loop.
You cannot copy the contents of one array to another using the = operator; you must use a library function like strcpy (for strings) or memcpy (for anything else), or you must assign each element individually:
as[0][1].val.cval[0] = 'T';
as[0][1].val.cval[1] = 'e';
as[0][1].val.cval[2] = 's';
...
as[0][1].val.cval[7] = 't';
as[0][1].val.cval[8] = 0;
Remember that in C, a string is a sequence of character values terminated by a 0-valued byte. Strings (including string literals like "Testtttt") are stored as arrays of char, but not all arrays of char store a string.

Strings in C: Why does this work?

I'm sorry for asking something that probably seems a little inane as it is apparently not broken but my (newbie) understanding of how C handles string literals tells me that this should not work...
char some_array_of_strings[3][200];
strcpy(some_array_of_strings[2], "Some garbage");
strcpy(some_array_of_strings[2], "Some other garbage");
I thought that C prevented the direct modification of string literals and that was why pointers were used when dealing with strings. The fact that this works tells me I am misunderstanding something.
Also, if this works, why does...
some_array_of_strings[1]="Some garbage"
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment"
not work?
Be careful with the phrase "array of strings". A "string" is not a data type in C; it's a data layout. Specifically, a string is defined as
a contiguous sequence of characters terminated by and including the
first null character
An array of char may contain a string, and a char* pointer may point to (the first character of) a string. (The standard defines a pointer to the first character of a string as a pointer to a string.)
char some_array_of_strings[3][200];
This defines a 3-element array, where each of the elements is a 200-element array of char. (It's a 2-dimensional array, which in C is simply an array of arrays.)
strcpy(some_array_of_strings[2], "Some garbage");
The string literal "Some garbage" refers to an anonymous statically allocated array of char; it exists for the entire execution of your program, and you're not allowed to modify it. The strcpy() call, as the name implies, copies the contents of that array, up to and including the terminating '\0' null character, into some_array_of_strings[].
strcpy(some_array_of_strings[2], "Some other garbage");
Same thing: this copies the contents "Some other garbage" into some_array_of_strings[2], overwriting what you copied on the previous line. In both cases, there's more than enough room.
You're not modifying a string literal, you're modifying your own array by copying bytes from a string literal (more precisely, from that anonymous array I mentioned above).
some_array_of_strings[1]="Some garbage";
This doesn't just "not work", it's illegal. There is no assignment of arrays in C.
Let's take a simpler example:
char arr[10];
arr = "hello"; /* also illegal */
arr is an object of array type. In most contexts, an expression of array type is implicitly converted to a pointer to the array object's first element. That applies to both sides of the assignment: the object name arr and the string literal "hello".
But the pointer on the left side is just a pointer value. There is no pointer object. In technical terms, it's not an lvalue, so it can't appear on the left side of an assignment any more than you could write 42 = x;).
(If the array-to-pointer conversion didn't happen, it would still be illegal, because C doesn't permit array assignments.)
Some more detail on the issue of arrays on the left side of assignment:
The contexts where an array expression doesn't decay into a pointer are when the array expression is:
an operand of the unary sizeof operator;
an operand of unary & (address-of) operator; or
a string literal in an initializer used to initialize an array object.
The left side of an assignment isn't any of those contexts, so in:
char array[10];
array = "hello";
LHS is, in principle, converted to a pointer. But the resulting pointer expression is no longer an lvalue, which makes the assignment a constraint violation.
One way to look at it is that the expression array is converted to a pointer, which then makes the assignment illegal. Another is that since the assignment is illegal, the whole program is not valid C, so it has no defined behavior and it's meaningless to ask whether any conversion does or does not happen.
(I'm playing a little fast and loose with my use of the word "illegal", but this answer is long enough already so I won't get into it.)
Recommended reading: Section 6 of the comp.lang.c FAQ; it does an excellent job of explaining the often bewildering relationship between arrays and pointers in C.
you aren't modifying the string literal, you are using it as a source to copy it into your array of characters. Once the copy is finished, your string literal has nothing to do with the copy in your array. You are free to then manipulate the array.
From your definition, char some_array_of_strings[3][200]; indicates that some_array_of_strings is an array of 3 elements, each of which is itself an array of 200 characters or strings of length 200 characters.
strcpy(some_array_of_strings[2], "Some garbage");
strcpy(some_array_of_strings[2], "Some other garbage");
In these 2 statements, you are actually copying the content from one char pointer to another char pointer which is valid. some_array_of_strings[2] is actually similar to char[200] which is similar to char *.
some_array_of_strings[1]="Some garbage";
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment";
Here, you are assigning a char * like "Some garbage" to a char[200] i.e. some_array_of_strings[1] which is not supported. The difference lies in assigning and copying the content.
some_array_of_strings[1]="Some garbage"
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment"
In the first line you assign some_array_of_strings[1] to a string literal so the address of some_array_of_strings[1] or &some_array_of_strings[1] points to a string literal. So in the second line when you try to reassign some_array_of_strings[1] it gives you the error.
It is just as Keith and Fred have said, with strcpy you are only copying the characters of the string literal into you array.
some_array_of_strings[2] is an array of 200 chars.
When it's used in most expressions, it "decays" (fancy word for converts) into a pointer to the first element of the array.
strcpy(some_array_of_strings[2], "Some garbage"); then copies "Some garbage" character by character into that array of 200 chars, by making use of the pointer to the first element of the array and advancing it one by one.
In most expressions "Some garbage" is a pointer to an array of chars containing those respective characters plus a string termination character ('\0').
some_array_of_strings[1]="Some garbage" on the other hand attempts to assign a pointer (to the string) to the constant/non-modifiable pointer to the first element of 200 chars, which is also illegal (like doing 1=2;)

Sizeof doesn't return the true size of variable in C

Consider the following code
#include <stdio.h>
void print(char string[]){
printf("%s:%d\n",string,sizeof(string));
}
int main(){
char string[] = "Hello World";
print(string);
}
and the output is
Hello World:4
So what's wrong with that ?
It does return the true size of the "variable" (really, the parameter to the function). The problem is that this is not of the type you think it is.
char string[], as a parameter to a function, is equivalent to char* string. You get a result of 4 because that is the size, on your system, of a char*.
Please read more here: http://c-faq.com/aryptr/index.html
It is the size of the char pointer, not the length of the string.
Use strlen from string.h to get the string length.
string is a pointer and its size is 4. You need strlen probably.
a array will change into a pointer as parameter of function in ANSI C.
Except when it is an operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an array expression will have its type implicitly converted ("decay") from "N-element array of T" to "pointer to T" and its value will be the address of the first element in the array (n1256, 6.3.2.1/3).
The object string in main is a 12-element array of char. In the call to print in main, the type of the expression string is converted from char [12] to char *. Therefore, the print function receives a pointer value, not an array. In the context of a function parameter declaration, T a[] and T a[N] are both synonymous with T *; note that this is only true for function parameter declarations (this is one of C's bigger misfeatures IMO).
Thus, the print function is working with a pointer type, not an array type, so sizeof string returns the size of a char *, not the size of the array.
A string in c is just an array of characters. It isn't necessarily NUL terminated (although in your case it is). There is no way for the function to know how long the string is that's passed to it - it's just given the address of the string as a pointer.
"String" is that pointer and on your machine (a 32 bit machine) it takes 4 bytes to store a pointer. So sizeof(string) is 4
You asked the systems for the sizeof(the address to the begining of a character array), string is an object, to get information about it's lenght out you have to ask it through the correct OO interface.
In the case of std::string the member function string.length(), will return the number of characters stored by the string object.
http://www.java2s.com/Code/Cpp/Data-Type/StringSizeOf.htm
see here it has same output as yours...and find what ur doing wrong

Resources