14

Given pointers to char, one can do the following:

char *s = "data";

As far as I understand, a pointer variable is declared here, memory is allocated for both variable and data, the latter is filled with data\0 and the variable in question is set to point to the first byte of it (i. e. variable contains an address that can be dereferenced). That's short and compact.

Given pointers to int, for example, one can do this:

int *i;
*i = 42;

or that:

int i = 42;
foo(&i); // prefix every time to get a pointer
bar(&i);
baz(&i);

or that:

int i = 42;
int *p = &i;

That's somewhat tautological. It's small and tolerable with one usage of a single variable. It's not with multiple uses of several variables, though, producing code clutter.

Are there any ways to write the same thing dry and concisely? What are they? Are there any broader-scope approaches to programming, that allow to avoid the issue entirely? May be I should not use pointers at all (joke) or something?

nobody
  • 19,814
  • 17
  • 56
  • 77
user3849273
  • 221
  • 1
  • 2
  • 7
  • In C, arguments to functions are passed _by value_, not _by reference_ (do a search on that), you need pointers to get the behavior of the latter; and you need pointers to handle arrays (because they decay to pointers in many cases). Besides that, I'm sure, this is a duplicate. – mafso Jul 17 '14 at 14:09
  • Isn't that one of the main reasons to have pointers? We pass values of pointer variables (memory addresses) instead of values pointed by them. I agree, but I don't understand how this is relevant. – user3849273 Jul 17 '14 at 14:29
  • To me, your question seemed to ask (besides other things) what pointers are good for at all (_“Maybe I should not use pointers at all (joke) or something”_)… Sorry, if I got you wrong. – mafso Jul 17 '14 at 14:43
  • I was not serious about not using pointers in C. I did ask whether there are any out-of-the-box answers. – user3849273 Jul 17 '14 at 14:50
  • Ah, now I got your question. Sorry for the confusion. – mafso Jul 17 '14 at 14:55

4 Answers4

29

String literals are a corner case : they trigger the creation of the literal in static memory, and its access as a char array. Note that the following doesn't compile, despite 42 being an int literal, because it is not implicitly allocated :

int *p = &42;

In all other cases, you are responsible of allocating the pointed object, be it in automatic or dynamic memory.

int i = 42;
int *p = &i;

Here i is an automatic variable, and p points to it.

int * i;
*i = 42;

You just invoked Undefined Behaviour. i has not been initialized, and is therefore pointing somewhere at random in memory. Then you assigned 42 to this random location, with unpredictable consequences. Bad.

int *i = malloc(sizeof *i);

Here i is initialized to point to a dynamically-allocated block of memory. Don't forget to free(i) once you're done with it.

int i = 42, *p = &i;

And here is how you create an automatic variable and a pointer to it as a one-liner. i is the variable, p points to it.

Edit : seems like you really want that variable to be implicitly and anonymously allocated. Well, here's how you can do it :

int *p = &(int){42};

This thingy is a compound literal. They are anonymous instances with automatic storage duration (or static at file scope), and only exist in C90 and further (but not C++ !). As opposed to string literals, compound literals are mutable, i.e you can modify *p.

Edit 2 : Adding this solution inspired from another answer (which unfortunately provided a wrong explanation) for completeness :

int i[] = {42};

This will allocate a one-element mutable array with automatic storage duration. The name of the array, while not a pointer itself, will decay to a pointer as needed.

Note however that sizeof i will return the "wrong" result, that is the actual size of the array (1 * sizeof(int)) instead of the size of a pointer (sizeof(int*)). That should however rarely be an issue.

Community
  • 1
  • 1
Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Is it possible to do like `int * i = {42}` or something, not duplicating variables? – user3849273 Jul 17 '14 at 14:15
  • @user3849273: No, because `i` needs to point to an *object* that contains the value 42. – John Bode Jul 17 '14 at 14:18
  • @JohnBode Actually... there's a way. Stay tuned for edit. (dun dun dun) – Quentin Jul 17 '14 at 14:19
  • Thanks, compound literals seem to be another valid way. But they are probably even less clear. May be I should use some sort of macro instead, like `PINT(i, 42);`? But it will obscure a variable declaration as a function call, won't it? – user3849273 Jul 17 '14 at 14:36
  • @user3849273 That would be quite a bad idea indeed. But say, what exactly are you trying to achieve ? We're at the border of C sanity here, and it would be cool to know before leaping into preprocessor madness. – Quentin Jul 17 '14 at 14:39
  • Well, I just want to declare and initialize all pointers as clear as pointers to char. I don't want to have a variable that will be used only once like in `int i = 42; int * p = &i`. – user3849273 Jul 17 '14 at 14:46
  • @user3849273 as you have seen, `char*` direct initialization is made possible by the implicit allocation of the literal. So the only solution is to use implicitly allocated literals. But the usual way is to just allocate variables, and take their address only when needed (your third code snippet). These `&` are no harm, and everyone understands what's going on, as opposed to compound literals, faux-arrays or dirty macros. – Quentin Jul 17 '14 at 14:52
  • @Quentin: Please edit your last addition (`int i[] = {42};`). The misconception of arrays being pointers (and vice-versa) is all too common. Best to make it clear from the start that arrays and pointers are 2 different things indeed. Perhaps explain why `sizeof i` and `sizeof(ptr);` aswell as how you can't determine the lenght of an array using a pointer, whereas `sizeof array/sizeof *array` will give the array size... – Elias Van Ootegem Jul 17 '14 at 15:02
  • @EliasVanOotegem I'm fully aware of the difference (and upped you down there :p). I feel like my last paragraph is not ambiguous, but I will expand on the `sizeof` issue. Feel free to suggest edits :) – Quentin Jul 17 '14 at 15:05
  • @Quentin: I assumed _you_ know the difference between arrays and pointers, but it's just that, adding a reference to an answer that suggests arrays and pointers are the same thing is like condoning such statements. The OP clearly is still in the early stages of learning C, and the confusion (and outright misinformation) concerning pointers is best avoided, IMHO. Hence my previous comment :) – Elias Van Ootegem Jul 17 '14 at 15:11
  • @EliasVanOotegem the idea was good (hadn't thought of arrays), the explanation was wrong, I couldn't go without giving credit and I can't state that it barely "inspired" me. Or can I. – Quentin Jul 17 '14 at 15:15
  • @Quentin: it's all good... sorry for nit-picking, but this array-names are pointers pitfall is one I encountered when first learning C. It wasn't until that distinction was made clear to me, that I truly understood pointers (and pointer arithmetic). Once that was cleared up, pointers became easy play-things, and I've been trying to point people in the direction of _correct_ information, so they don't have to spend as much time learning about pointers as I have. That's all. Again: sorry for the nitpicking, and +1 for your trouble – Elias Van Ootegem Jul 17 '14 at 15:20
  • 1
    @EliasVanOotegem My pleasure. Such nitpicking is a little time spent from which everyone benefits (myself included : crystal clear answers are hard to get right, and practice makes perfect). – Quentin Jul 17 '14 at 15:25
3
int i=42;
int *ptr = &i;

this is equivalent to writing

int i=42;
int *ptr;
ptr=&i;

Tough this is definitely confusing, but during function calls its quite useful as:

void function1()
{
int i=42;
function2(&i);
}

function2(int *ptr)
{
printf("%d",*ptr); //outputs 42
}

here, we can easily use this confusing notation to declare and initialize the pointer during function calls. We don't need to declare pointer globally, and the initialize it during function calls. We have a notation to do both at same time.

int *ptr; //declares the pointer but does not initialize it
//so, ptr points to some random memory location
*ptr=42; //you gave a value to this random memory location

Though this will compile, but it will invoke undefined behaviour as you actually never initialized the pointer.

Also,

char *ptr;
char str[6]="hello";
ptr=str;

EDIT: as pointed in the comments, these two cases are not equivalent. But pointer points to "hello" in both cases. This example is written just to show that we can initialize pointers in both these ways (to point to hello), but definitely both are different in many aspects.

char *ptr;
ptr="hello";

As, name of string, str is actually a pointer to the 0th element of string, i.e. 'h'. The same goes with any array arr[], where arr contains the address of 0th element.

nishantbhardwaj2002
  • 757
  • 2
  • 6
  • 18
  • 2
    Dangerously wrong. `char str[6]="hello";` declares a `char` array where "hello" is copied. This array is automatic and mutable. OTOH, `ptr="hello";` makes p point to the string literal "hello", which is static and non-mutable. – Quentin Jul 17 '14 at 14:29
  • I am telling about pointer ptr, which in both cases points to a string "hello". Tough, thanks for pointing it out, so that the readers don't get confused :) – nishantbhardwaj2002 Jul 17 '14 at 14:31
  • 1
    Indeed both strings read "hello", but that does not suffice to make both code snippets equivalent. Say you want to modify the string, or `return p;` ? The differences will appear as crashes, or worse. So you should definitely care. – Quentin Jul 17 '14 at 14:37
  • I double Quentin, these two last cases are not equivalent and such thinking can lead to very nasty runtime errors. Please edit your answer to reflect that or I'll have to downvote you. – KBart Jul 17 '14 at 14:48
  • edited. Though the example was given just to state that pointer will point to "hello" in both cases, i think the word "equivalent" lead to this confusion. thanks for pointing it out. – nishantbhardwaj2002 Jul 17 '14 at 14:56
  • The real problem is that if you try to edit through the pointer in the second case, you will get runtime error or in other words, your program will crash. For example, *ptr[0]='a'* is a valid sentence in the first case, but the same statement leads to crash in the second. – KBart Jul 17 '14 at 15:11
0
int * i;
*i = 42; 

will invoke undefined behavior. You are modifying an unknown memory location. You need to initialize pointer i first.

int i = 42;
int *p = &i;

is the correct way. Now p is pointing to i and you can modify the variable pointed to by p.

Are there any ways to write the same thing dry and concisely?

No. As there is no pass by reference in C you have to use pointers when you want to modify the passed variable in a function.

Are there any broader-scope approaches to programming, that allow to avoid the issue entirely? May be I should not use pointers at all (joke) or something?

If you are learning C then you can't avoid pointers and you should learn to use it properly.

haccks
  • 104,019
  • 25
  • 176
  • 264
0

you can also think it as array , int i[1]={42} where i is a pointer to int

Luca Rocchi
  • 6,272
  • 1
  • 23
  • 23
  • 3
    This will work, but don't be fooled: arrays are not pointers. They decay into pointers, and can be used as pointers, too, but they are **not** the same thing: [Details here](http://stackoverflow.com/questions/4607128/in-c-are-arrays-pointers-or-used-as-pointers) – Elias Van Ootegem Jul 17 '14 at 14:55