Reputation: 54846
I've been working hard to get more familiar with C this week. I've been reading C Primer Plus (5th Edition) but I'm still having a bit of trouble with variables and pointers.
Here is my script that I'm using to test:
int main (int argc, char **argv) {
char *myvariable=NULL;
myvariable = strdup("apples");
myvariable = strdup("value updated");
printf("========== \n\n");
printf("this is the thing : %p \n", myvariable);
printf("this is the thingval: %s \n", myvariable);
setvariable(&myvariable);
printf("after function - this is the thing : %p \n", myvariable);
printf("after function - this is the thingval: %s \n", myvariable);
return 0;
}
int setvariable(char **myvariable) {
*myvariable = strdup("value from function");
return 1;
}
Output from running it gives me:
this is the thing : 0x7fee9b4039c0
this is the thingval: value updated
after function - this is the thing : 0x7fee9b4039d0
after function - this is the thingval: value from function
Does char *myvariable=NULL;
mean that myvariable
is a pointer or a variable? This answer says The form char *ptr = "string";
is just backwards compatibility for const char *ptr = "string";
With the function setvariable(char **myvariable)
- is **myvariable
a "pointer to a pointer" ?
Or is myvariable
actually just a string (nul terminated array of characters) ?
This is some code that I've found (no documentation) so I have a lot of questions about it. The next one is why is myvariable
defined this way - and would it not be better to set it up like one of these ways:
char myvariable[] = "apples";
char myvariable[6] = "apples";
I also don't understand why when setvariable
is called it appears to be passing in the address of myvariable with &
- wouldn't it be better to pass a pointer?
I've tried to do research on this before asking - but after two days progress has been slow and I'd like a little advice.
Clarification for Asking
The reason I'm asking is because form what I've read it looks like if something has a *
after it, like char *myvariable
then it should be a pointer.
However, I am having trouble creating a char
that is not a pointer and assigning the myvariable
pointer to point to it.
Upvotes: 2
Views: 1747
Reputation: 123558
Does char *myvariable=NULL; mean that myvariable is a pointer or a variable?
myvariable
is a variable of type "pointer to char
". It will be used to store the address of an object of type "char".
This answer says The form char *ptr = "string"; is just backwards compatibility for const char *ptr = "string";
Backwards compatibility from what?
The string literal expression "string"
has type "7-element array of char
" (6 characters plus 0 terminator). In C, an expression of type "N-element array of T
" will be converted to an expression of type "pointer to T
" and it's value will be the address of the first element in the array, except when the array expression is the operand of the sizeof
or unary &
operator, or is a string literal being used to initialize another array in a declaration.
So when you write
char *ptr = "string";
the expression "string"
is not the operand to a sizeof
or unary &
operator, nor is it being used to initialize an array in a declaration, so its type is converted from "7-element array of char
" to "pointer to char
", and the pointer value (address of the first element of the array) is copied to ptr
.
One issue with C is that attempting to modify the contents of a string literal invokes undefined behavior. Some platforms put string literals in read-only memory, some don't; some create multiple instances of the literals if multiple instances exist in the code, some only create a single instance on the literal. Therefore trying to modify the literal may work on some platforms, cause an access violation on others, result in unpredictable behavior on others, etc. The C language standard explicitly leaves the behavior undefined, so that implementations are free to handle the situation any way they see fit.
As a safety measure, most people explicitly declare the pointer to be const char *
:
const char *ptr = "string";
that way you cannot modify the string contents through ptr
. Note that C++ is different in the respect that string literals have type "array of const char
", so those expressions will be converted to const char *
anyway.
The reason I'm asking is because form what I've read it looks like if something has a * after it, like char *myvariable then it should be a pointer.
In C (and C++), declarations are based on the types of expressions; the form of the expression in a declaration matches the form of an expression in the code.
For example, if we have a pointer variable named p
that points to an int
, and we want to access that integer value, we dereference the pointer with the unary *
operator:
x = *p;
The type of the expression *p
is int
, so the declaration of the variable p
is
int *p;
The type of the variable p
is "pointer to int
". The int
-ness of p
is given by the type specifier int
; the pointer-ness of p
is given by the declarator *p
. Note that the *
is bound to the identifier, not the type specifier; even though you can write the declaration as
int* p;
it's interpreted as
int (*p);
Upvotes: 1
Reputation: 76735
char c; // allocates a variable with space to hold one character
char *p; // allocates a pointer that may point to a character
p = &c; // sets variable p to point to the storage allocated for c
c = 'a'; // stores character 'a' in the storage allocated for c
*p = 'a'; // has exact same result as previous
char const *mesg = "abcd";
// allocates 5 characters ('a', 'b', 'c', 'd', '\0')
// also allocates a pointer that may point to a character
// also makes the pointer point to the literal string "abc"
char buf5[] = "abcd";
// Allocates 5 characters ('a', 'b', 'c', 'd', '\0')...
// the compiler figures out how many values need to go in the array.
// Variable buf5 is a reference to this array
char x5[] = { 'a', 'b', 'c', 'd', '\0' };
// has exact same result as previous
sizeof(buf5) // evaluates to the value 5
int i5[5];
sizeof(i5) // evaluates to: sizeof(int) * 5
sizeof(buf5) // evaluates to: sizeof(char) * 5
// but sizeof(char) is always 1 (by definition!)
sizeof(p) // evaluates to size of a pointer (probably 4 or 8)
// size of pointer does not change no matter which string it points to
buf5[0] = 'A'; // now s3 holds: "Abcd"
*buf5 = 'A'; // has exact same result as previous
buf5[1] = 'B'; // now s3 holds: "ABcd"
*(buf5 + 1) = 'B'; // has exact same result as previous
You can easily overwrite the characters in the char array buf5
but you cannot increase the size of the storage allocated for it; you can only reuse the existing storage.
When you declare an array, you "own" the storage; C sets it up for you. When you use a literal string, you might or might not be able to get away with writing to it, and it's best not to try. The literal might be put somewhere special (like in ROM on an embedded system) and it may not even be possible to write to it, so any program that depends on writing to a literal is needlessly nonportable.
As for the notation...
In C when you are using a pointer, if you put a *
in front of it you dereference the pointer. This lets you examine what the pointer is pointing to, or modify it.
When you are declaring a pointer, in C you declare it using the same syntax, which is kind of tricky. But here are some examples:
char c; // c has the type char
char *p; // when you dereference the pointer p, you get type char
// Assume p contains garbage right now; we have no idea where it might point
c = 'a'; // legal: assigning a char value to a char type
*p = 'a'; // legal just as above
p = &c; // p now points to the storage for variable c
char **pp; // pp is a pointer to a pointer to char
// If you dereference pp twice you get a char
// If you dereference pp once you get a char *, a pointer to char
// Assume pp contains garbage right now; we have no idea where it might point
pp = &p; // pp now points to the storage of p (which is a pointer pointing to c)
*p = 'a'; // dereference p to find the char to assign (variable c)
*(*pp) = 'a'; // dereference pp to find p, dereference p in turn to find char to assign
**pp = 'a'; // parentheses not required, same as previous line
In C, functions are always call by value: arguments to the function are copied. So, to modify something from inside a function, you pass a pointer; the pointer is copied, but then the value of the pointer is used to find the variable you want to modify.
Confusingly, your example function wants to modify a pointer. Thus, you declare that it takes a char **
, and you take the address of the pointer when calling the function.
Upvotes: 0
Reputation: 2812
char* myvariable
- char*
is setting up a pointer to a memory location that holds an object of type char
myvariable
is a variable used to reference that location.
To get at the value you have to de-reference using &myvariable
I did C++ over 10 years ago, not C, but I think thats reasonably accurate.
Upvotes: 0
Reputation: 23717
Does char *myvariable=NULL; mean that myvariable is a pointer or a function?
myvariable
is a pointer (ie a variable, since a pointer is a variable).
1) Is that true?
I don't think it is really backwards compatibility. However, a string litteral such as "string"
behaves as a constant string.
2) Am I creating a constant character?
Trying to modify the characters of the string "string"
is an undefined behavior. There is no const
, because the type of an anonymous string is char[]
. But programmers often advise to declare it as const
, to prevent errors.
3) Aren't those supposed to be immutable? If so why can I update the value?
You can't modifiy *myvariable
(as long as it is assigned to a string litteral), but you can modify the pointer myvariable
.
With the function setvariable(char **myvariable) - is **myvariable a "pointer to a pointer" ?
Yes, it is.
Or is myvariable actually just a string (nul terminated array of characters) ?
*myvariable
is a string and a pointer to char
.
By the way, I guess you should read this answer.
Upvotes: 2
Reputation: 179592
By writing char *myvariable
, int foo
, double blah
, or void (*funcptr)(void)
, you are declaring a variable with some type. The type of the variable specifies what is stored in that variable: a pointer, number, or structure.
So, char *myvariable
is a variable (some reserved amount of memory) that contains a pointer value.
Upvotes: 0