cwd
cwd

Reputation: 54846

Is a variable defined with "char *" a pointer or a variable of type char in c?

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 

Questions

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";

  1. Is that true?
  2. Am I creating a constant character?
  3. Aren't those supposed to be immutable? If so why can I update the value?

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

Answers (5)

John Bode
John Bode

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

steveha
steveha

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

Ian Robertson
Ian Robertson

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

md5
md5

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

nneonneo
nneonneo

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

Related Questions