Why is the following code invalid? - c

Why is the following code invalid?
void foo()
{
char hello[6];
char *foo = "hello";
hello = foo;
}
But how the following code is valid?
void foo()
{
char hello[] = "hello";
char *foo = hello;
}

You are are trying to assign the array as a pointer. This is invalid. Arrays are like pointer constants in that they can’t be used as lvalues – they can’t be reassigned to point to somewhere else. The closest you can get is to copy the contents of foo into hello.
In second case, hello is an array of chars and foo is a pointer to a char. In general, arrays are interchangeable with pointers of the same type so this is valid.

I think you supposed string "hello" will be copied to hello. It's wrong. You're trying to assign a pointer to another. And, you can not assign to hello.
The right way is:
strcpy(hello, foo);

In first case you are assigning string to a foo pointer that is wrong.
where as in 2nd case you have an array of char and you are passing it into foo pointer

Related

Why do I get "Incompatible types when assigning" error?

I'm having C code which seems to have similar pointer assignments but shows different behaviours while compiling .
My structure declaration and definition is below,
typedef struct {
int a;
char b[20];
}
TestStruct;
TestStruct t1;
Why does the below code gives "error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’"
t1.b = "Hello World";
but the code below compiles successfully,
char *charPtr = t1.b;
charPtr = "Hello World";
Note: I'm using GCC compiler v4.6.3
Ths strings cannot be assigned to arrays in C, unless as part of an initialization.
The right way to do something like that is by means of the function strcpy() of ths <string.h> standard header.
strcpy(t1.b, "Hello world");
It is not true that the array t1.b is a pointer to char.
Actually, it has type array of 20 elements of type char.
In an expression, the array normally decays to a pointer to char.
However, the array has a fixed address in memory. It is not an lvalue, its address cannot be changed by an assignment.
The opposite assignment is valid:
charPtr = "Hello World";
The address of the string "Hello world" is assigned to charPtr.
However, your sentences have not the intended effect:
char *charPtr = t1.b;
charPtr = "Hello World";
The effect is that charPtr becomes equal to the address of t1.b.
Then, this value is discarded in the second sentence and replaced by the address of the array "Hello world".
More details: Be carefull in handling strings. A string literal like "Hello world" is an array stored (in general) in only-read memory. If you try to modify it, you can obtain unexpected results.
In particular, this happens with the assignment charPtr = "Hello world".
The string can be read, but not changed.
To change or manipulate a string, it has to be copied (with strcpy()) to an array or to an allocated portion of memory.
You can't directly assign a string literal to a char array. Use strcpy() or strlcpy().
In the second example, the array decays into a pointer, and then you change that pointer. Note that in this example, t1.b remains unchanged.
When you define:
typedef struct {
int a;
char b[20];
}TestStruct;
b is a constant pointer pointing to char. Hence t1.b = "Hello World"; is a compiling error since it change the value of t1.b
Solutions:
1) Use strcpy:
strcpy(t1.b, "Hello World");
2) Tricky type-casting way
char** pb = (char**)&t1.b;
*pb = "Hello World";
Although these 2 methods bring the same purpose (setting t1.b to "Hello World" string), the underlying idea is very different.
You cannot assign const char* to char[] as it violates constancy.

manipulating what the pointer is pointing at

This is probably a really easy question but I can not seem to find an explicit answer online. Say a had a pointer to an array declared as:
static char newMessage[400];
char *p = &newMessage;
(I don't know if this is right) How would I go about manipulation the newMessage array using only the pointer. I am doing this because a C cannot return an array but can return a pointer to an array. please be gentle, I'm new
Your code is almost right; the only problem is that you have mismatched pointer types. You want:
char *p = newMessage;
Not:
char *p = &newMessage;
The latter tries to initialize p, a char * variable, with a value of type char (*)[400], which isn't valid C.
After you've created and initialized p, you can just use it however you'd like:
p[6] = 12;
Or something like that.
Just point the pointer to the array
char* p = newMessage ;
And return it from a function.
You use it the same as you would use the array it points to.
newMessage[2] = '\0'
p[2] = '\0'
When you declare an array like static char newMessage[400], the identifier newMessage is substituted by the address of the first element of the array, and it behaves like a pointer.
char* p= newMessage;
char* q= "Hi, world";
newMessage[4]= 'x';
p[4]= 'x';
*(newMessage + 2)= 0;
*(p+2)= 0;
strlen(newMessage);
strlen(q);
strcmp(newMessage, "Hi world");
strcmp(p, q);
are all valid expressions.
Note that in the last four function calls, you are not passing arrays, but pointers to the first character of the string. And by convention, the functions scan the memory until they find a null byte terminator.
Actually, it should be char *p = newMessage; .The char[] behaves similar to char*.
You'll later modify it by how you usually modify any pointer.
BTW, this is very basic so it's better you read a tutorial.
Also, since you asked this, if you're planning to return a pointer to the array, the array better not be allocated on the stack. It should be heap-allocated (it's in your case since static)
You cannot actually manipulate the array, as arrays are no first class type in c.
Almost anything you care to do with the array name, will make it degenerate to a pointer. The exception being sizeof, so you can get the element count using sizeof array/sizeof *array.
What you can do, is change the values of the array elements. Use pointer arithmetic and dereferencing *. The index operator a[b] is syntactic sugar for *(a+b).
Also, you can use library functions (or your own), which accept pointers.

Pointer to array of string

I don't understand this part of code:
char *arrStr[3];
arrStr[0] = "hola"; //works
*(arrStr+1) = "guys"; //works
arrStr++; // doesn't work why?
char **arrStr2 = arrStr; //works
arrStr2++; //works
I don't understand why arrStr++ doesn't work while arrStr2 works.
This is strange because I'm doing the same thing, but in one case it works in the other not, why is that?
*arrStr[3] is an array of 3 pointers to char while **arrStr2 a pointer to a pointer to char. In
arrStr[0] = "hola";
arrStr is an array and array names are nonmodifiable l-values and hence you can't modify it. On the other hand modification can be done on arrStr as it is a pointer to pointer but not an array. Do remember that arrays are not pointers.
arrStr is an array of pointers, you can't modify an array name. arrStr++; won't compile.
arrStr2 is a pointer to a pointer, you can modify a pointer. And you should consider a better name, as it's not an array.
char *arrStr[3];
if you use the array name as a pointer,you must know that this pointer is a const pointer, so you can't do the ++ or -- operator, char *str = "ciao"; just declare a normal pointer, you can do every to it.

string array initialisation

This is a continuation of another question I have.
Consider the following code:
char *hi = "hello";
char *array1[3] =
{
hi,
"world",
"there."
};
It doesn't compile to my surprise (apparently I don't know C syntax as well as I thought) and generates the following error:
error: initializer element is not constant
If I change the char* into char[] it compiles fine:
char hi[] = "hello";
char *array1[3] =
{
hi,
"world",
"there."
};
Can somebody explain to me why?
In the first example (char *hi = "hello";), you are creating a non-const pointer which is initialized to point to the static const string "hello". This pointer could, in theory, point at anything you like.
In the second example (char hi[] = "hello";) you are specifically defining an array, not a pointer, so the address it references is non-modifiable. Note that an array can be thought of as a non-modifiable pointer to a specific block of memory.
Your first example actually compiles without issue in C++ (my compiler, at least).

Pointers, arrays and passing pointers to methods

Confused with the problem here. New to C, as made obvious by the below example:
#include <stdlib.h>
#include <stdio.h>
void pass_char_ref(unsigned char*);
int main()
{
unsigned char bar[6];
pass_char_ref(&bar);
printf("str: %s", bar);
return 0;
}
void pass_char_ref(unsigned char *foo)
{
foo = "hello";
}
To my understanding, bar is an unsigned character array with an element size of 6 set away in static storage. I simply want to pass bar by reference to pass_char_ref() and set the character array in that function, then print it back in main().
You need to copy the string into the array:
void pass_char_ref(unsigned char *foo)
{
strcpy( foo, "hello" );
}
Then when you call the function, simply use the array's name:
pass_char_ref( bar );
Also, the array is not in "static storage"; it is an automatic object, created on the stack, with a lifetime of the containing function's call.
Two things:
You don't need to pass &bar; just pass bar.
When you pass an array like this, the address of its first (0th) element is passed to the function as a pointer. So, call pass_char_ref like this:
pass_char_ref(bar);
When you call pass_char_ref like this, the array name "decays" into a pointer to the array's first element. There's more on this in this tutorial, but the short story is that you can use an array's name in expressions as a synonym for &array_name[0].
Pointers are passed by value. You have:
void pass_char_ref(unsigned char *foo)
{
foo = "hello";
}
In some other languages, arguments are passed by reference, so formal parameters are essentially aliases for the arguments. In such a language, you could assign "hello" to foo and it would change the contents of bar.
Since this is C, foo is a copy of the pointer that's passed in. So, foo = "hello"; doesn't actually affect bar; it sets the local value (foo) to point to the const string "hello".
To get something like pass by reference in C, you have to pass pointers by value, then modify what they point to. e.g.:
#include <string.h>
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
This will copy the string "hello" to the memory location pointed to by foo. Since you passed in the address of bar, the strcpy will write to bar.
For more info on strcpy, you can look at its man page.
In C, arrays are accessed using similar mechanics to pointers, but they're very different in how the definitions work - an array definition actually causes the space for the array to be allocated. A pointer definition will cause enough storage to be allocated to refer (or "point") to some other part of memory.
unsigned char bar[6];
creates storage for 6 unsigned characters. The C array semantics say that, when you pass an array to another function, instead of creating a copy of the array on the stack, a pointer to the first element in the array is given as the parameter to the function instead. This means that
void pass_char_ref(unsigned char *foo)
is not taking an array as an argument, but a pointer to the array. Updating the pointer value (as in foo = "hello";, which overwrites the pointer's value with the address of the compiled-in string "hello") does not affect the original array. You modify the original array by dereferencing the pointer, and overwriting the memory location it points to. This is something that the strcpy routine does internally, and this is why people are suggesting you use
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
instead. You could also say (for sake of exposition):
void pass_char_ref(unsigned char *foo)
{
foo[0] = 'h';
foo[1] = 'e';
foo[2] = 'l';
foo[3] = 'l';
foo[4] = 'o';
foo[5] = 0;
}
and it would behave correctly, too. (this is similar to how strcpy will behave internally.)
HTH
Please see here to an explanation of pointers and pass by reference to a question by another SO poster. Also, here is another thorough explanation of the differences between character pointers and character arrays.
Your code is incorrect as in ANSI C standard, you cannot pass an array to a function and pass it by reference - other data-types other than char are capable of doing that. Furthermore, the code is incorrect,
void pass_char_ref(unsigned char *foo)
{
foo = "hello";
}
You cannot assign a pointer in this fashion to a string literal as pointers use the lvalue and rvalue assignment semantics (left value and right value respectively). A string literal is not an rvalue hence it will fail. Incidentally, in the second link that I have given which explains the differences between pointers and arrays, I mentioned an excellent book which will explain a lot about pointers on that second link.
This code will probably make more sense in what you are trying to achieve
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
In your main() it would be like this
int main()
{
unsigned char bar[6];
pass_char_ref(bar);
printf("str: %s", bar);
return 0;
}
Don't forget to add another line to the top of your code #include <string.h>.
Hope this helps,
Best regards,
Tom.
Since bar[] is an array, when you write bar, then you are using a pointer to the first element of this array. So, instead of:
pass_char_ref(&bar);
you should write:
pass_char_ref(bar);
Time again for the usual spiel --
When an expression of array type appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T" and its value is set to point to the first element of the array. The exceptions to this rule are when the array expression is the operand of either the sizeof or & operators, or when the array is a string litereal being used as an initializer in a declaration.
So what does all that mean in the context of your code?
The type of the expression bar is "6-element array of unsigned char" (unsigned char [6]); in most cases, the type would be implicitly converted to "pointer to unsigned char" (unsigned char *). However, when you call pass_char_ref, you call it as
pass_char_ref(&bar);
The & operator prevents the implicit conversion from taking place, and the type of the expression &bar is "pointer to 6-element array of unsigned char" (unsigned char (*)[6]), which obviously doesn't match the prototype
void pass_char_ref(unsigned char *foo) {...}
In this particular case, the right answer is to ditch the & in the function call and call it as
pass_char_ref(bar);
Now for the second issue. In C, you cannot assign string values using the = operator the way you can in C++ and other languages. In C, a string is an array of char with a terminating 0, and you cannot use = to assign the contents of one array to another. You must use a library function like strcpy, which expects parameters of type char *:
void pass_char_ref(unsigned char *foo)
{
strcpy((char *)foo, "hello");
}
Here's a table of array expressions, their corresponding types, and any implicit conversions, assuming a 1-d array of type T (T a[N]):
Expression Type Implicitly converted to
---------- ---- -----------------------
a T [N] T *
&a T (*)[N]
a[0] T
&a[0] T *
Note that the expressions a, &a, and &a[0] all give the same value (the address of the first element in the array), but the types are all different.
The use of the address of operator (&) on arrays is no longer allowed. I agree that it makes more sense to do &bar rather than bar, but since arrays are ALWAYS passed by reference, the use of & is redundant, and with the advent of C++ the standards committee made it illegal.
so just resist the urge to put & before bar and you will be fine.
Edit: after a conversation with Roger, I retract the word illegal. It's legal, just not useful.

Resources