6

I've been looking through the site but haven't found an answer to this one yet.

It is easiest (for me at least) to explain this question with an example.

I don't understand why this is valid:

#include <stdio.h>

int main(int argc, char* argv[])
{
  char *mystr = "hello";
}

But this produces a compiler warning ("initialization makes pointer from integer without a cast"):

#include <stdio.h>

int main(int argc, char* argv[])
{
  int *myint = 5;
}

My understanding of the first program is that creates a variable called mystr of type pointer-to-char, the value of which is the address of the first char ('h') of the string literal "hello". In other words with this initialization you not only get the pointer, but also define the object ("hello" in this case) which the pointer points to.

Why, then, does int *myint = 5; seemingly not achieve something analogous to this, i.e. create a variable called myint of type pointer-to-int, the value of which is the address of the value '5'? Why doesn't this initialization both give me the pointer and also define the object which the pointer points to?

sav0h
  • 381
  • 1
  • 4
  • 10

5 Answers5

11

In fact, you can do so using a compound literal, a feature added to the language by the 1999 ISO C standard.

A string literal is of type char[N], where N is the length of the string plus 1. Like any array expression, it's implicitly converted, in most but not all contexts, to a pointer to the array's first element. So this:

char *mystr = "hello";

assigns to the pointer mystr the address of the initial element of an array whose contents are "hello" (followed by a terminating '\0' null character). Incidentally, it's safer to write:

const char *mystr = "hello";

There are no such implicit conversions for integers -- but you can do this:

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

(int){42} is a compound literal, which creates an anonymous int object initialized to 42; & takes the address of that object.

But be careful: The array created by a string literal always has static storage duration, but the object created by a compound literal can have either static or automatic storage duration, depending on where it appears. That means that if the value of ptr is returned from a function, the object with the value 42 will cease to exist while the pointer still points to it.

As for:

int *myint = 5;

that attempts to assign the value 5 to an object of type int*. (Strictly speaking it's an initialization rather than an assignment, but the effect is the same). Since there's no implicit conversion from int to int* (other than the special case of 0 being treated as a null pointer constant), this is invalid.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    Is there any current or proposed method for declaring that a constant literal should have static duration [e.g. something like `&(static int){42};`]? Given that a string literal rvalue "Foo" is essential equivalent to a hoisted `static char[4] __string24601 = {'F','o','o',0};` followed by a reference to `__string24601`, compilers should already have a mechanism to provide such behavior. – supercat Jul 21 '15 at 20:10
  • Only thing you forget is that it is valid to assign an address (not `5` obviously) to a pointer. which is used a lot with embedded systems where memory mapped resources are commonly used. – Tomer W Jul 21 '15 at 20:14
  • @TomerW: Valid in what sense? Assigning an integer value other than a null pointer constant to a pointer object is a constraint violation. You can assign the result of converting such a value to a pointer type; that's just assigning a pointer to a pointer. (Some compilers are lax about integer-to-pointer assignments. If they don't at least warn about it, they're not conforming C compilers.) – Keith Thompson Jul 21 '15 at 20:24
  • @supercat: There's a proposed method only in the sense that I recently proposed it in comp.lang.c. I don't expect it to go anywhere. You can always `static int n = 42; int *ptr = &n;`. The language / compiler can't do *everything* for you. – Keith Thompson Jul 21 '15 at 20:26
  • @KeithThompson: There are many contexts where compound literals are usable but statements are not, so the above approach won't be usable in many function-like macro contexts (inline functions haven't totally displaced the latter, especially when it comes to things which may wish to e.g. generate log reports including `__FILE__` and `__LINE__`). I find the decision to give such constants automatic storage duration curious, actually; I wonder in what cases that would actually lead to more efficient code as compared with making them `static const`. – supercat Jul 21 '15 at 20:38
  • This is perfect - thank you. I was missing the understanding that string literals / char arrays implicitly convert to pointers to their first elements. Now I understand why the first case is valid and the second is not. – sav0h Jul 21 '15 at 20:45
  • @supercat, a compound literal is not a constant, unfortunately. One can do a bit better by using `(int const){ 42 }`. The compiler then *may* (to his liking) realize that compound literal in static storage. And then, all of this sounds pretty much like premature optimization to me. An optimizing compiler will probably have adapted strategies (to the number of registers, e.g) that will work better than most handcrafted coding. – Jens Gustedt Jul 21 '15 at 21:00
  • @JensGustedt: My desire for it to be static isn't to facilitate "optimization", but rather to allow a structure whose sole reason for existence is to hold some values to be given to a function to be defined at the place the function is called. For example, given `typedef struct { int length; char const [] content; } PXSTRING; PXSTRING const *msg;`, being able to say `msg = PX("Fred");` [with PX being a macro] seems much nicer than having to have a macro at declaration scope `MPX(fred_msg, "Fred");` and then say `msg = &fred_message.px;`. – supercat Jul 21 '15 at 21:18
  • @JensGustedt: If `PX` is a macro, it can invoke `sizeof` on the string argument and thus evaluate the desired length as a constant. It's possible even in C89 to use the style of macro which creates a new identifier `fred_msg` (which is actually a `union` that contains a `PXSTRING` along with a custom-defined structure that contains the proper length of `char[]`) but requiring the literal to be specified at a spot away from its use is icky. – supercat Jul 21 '15 at 21:23
  • @KeithThompson well, might be compilers that do not allow that, but most do. I, as RT SW Dev use it a lot! i have a lot of Hardware resources i access by their absolute addresses on the bus. e.g. if i have LED fixed to the 3rd bit of 0x80000000, i would certainly use `int* boardLEDRegister = (int*)0x80000000;` and later will turn the led on by `boardLEDRegister |= 0x4` – Tomer W Jul 21 '15 at 21:24
  • @TomerW: `int* boardLEDRegister = (int*)0x80000000;` is perfectly valid because of the cast (though its behavior is at best implementation-defined). Are you sure you don't mean `*boardLEDRegister |= 0x4`, which sets a bit of the word at address `0x80000000`? (BTW, I'd use `unsigned int`, and I'd use `const` unless the address can change.) – Keith Thompson Jul 21 '15 at 21:34
  • @Keith , yes.. i forgot the * – Tomer W Jul 22 '15 at 06:52
2

When you do char* mystr = "foo";, the compiler will create the string "foo" in a special read-only portion of your executable, and effectively rewrite the statement as char* mystr = address_of_that_string;

The same is not implemented for any other type, including integers. int* myint = 5; will set myint to point to address 5.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
1

i'll split my answer to two parts:

1st, why char* str = "hello"; is valid:

char* str declare a space for a pointer (number that represents a memory address on the current architecture)

when you write "hello" you actually fill the stack with 6 bytes of data
(don't forget the null termination) lets say at address 0x1000 - 0x1005.

str="hello" assigns the start address of that 5 bytes (0x1000) to the *str

so what we have is :
1. str, which takes 4 bytes in memory, holds the number 0x1000 (points to the first char only!)
2. 6 bytes 'h' 'e' 'l' 'l' 'o' '\0'

2st, why int* ptr = 0x105A4DD9; isn't valid:

well, this is not entirely true!
as said before, a Pointer is a number that represent an address,
so why cant i assign that number ?

it is not common because mostly you extract addresses of data and not enter the address manually.
but you can if you need !!!...
because it isn't something that is commonly done,
the compiler want to make sure you do so in propose, and not by mistake and forces you to CAST your data as
int* ptr = (int*)0x105A4DD9;
(used mostly for Memory mapped hardware resources)

Hope this clear things out.
Cheers

Tomer W
  • 3,395
  • 2
  • 29
  • 44
0

"In C, why can't an integer value be assigned to an int* the same way a string value can be assigned to a char*?"

Because it's not even a similar situation, let alone "the same way".

A string literal is an array of chars which – being an array – can be implicitly converted to a pointer to its first element. Said pointer is a char *.

But an int is not either a pointer in itself, nor an array, nor anything else implicitly convertible to a pointer. These two scenarios just don't have anything in common.

  • Yes I was not aware of the concept of implicit conversion - so was misled by the syntactic similarity between the two cases. Thanks for your help. – sav0h Jul 21 '15 at 20:50
-2

The problem is that you are trying to assign the address 5 to the pointer. Here you are not dereferencing the pointer, you are declaring it as a pointer and initializing it to the value 5 (as an address which surely is not what you intend to do). You could do the following.

#include <stdio.h>

int main(int argc, char* argv[])
{
  int *myint, b;
  b = 5;
  myint = &b;
}
Dan
  • 383
  • 1
  • 4
  • 1st, you wrote 0x5 to an address you dont know... so BIG NO-NO. 2nd, sometimes you do cast an uint32 to a ptr – Tomer W Jul 21 '15 at 19:56
  • My bad, fixed it. Dereferenced myint rather than assigning it to the address of b. – Dan Jul 22 '15 at 14:12