-3

I read this: Two different values at the same memory address and this: How is a variable at the same address producing 2 different values? but both are about problems with const qualifiers, so I think my question is different.

This is from a linked list implementation. head is a struct Node*, and walker, used to print list elements etc..., is also a struct Node* and is initialized as struct Node* walker = head.

What's weird is that if I print out *head with a %d format (my struct Node is a classic int value and struct Node* next format), I get 1, which is what I set up the value of the first Node to be. However, when I print out *walker using the same %d format, I get some weird decimal value such as 1525189360.

I check however that both head and walker hold the same value, which is the address of the first Node, so I really don't understand that discrepency.

What's even weirder is that if I print out head->value, I get 1 again, and if I print out walker->value, I also get 1 this time!

Code

struct Node {
    int value;
    struct Node* next;
};
struct Node n1;
n1.value = 1;
struct Node* head;
head = &n1;
struct Node* walker = head;

printf("address of walker: %p, address of head: %p, value in walker: %p \
        ,value in head: %p, value pointed to by walker: %d, value pointed \
        to by head: %d\n", &walker, &head, walker, head, *walker, *head);

Print Out:

address of walker: 0x7fff5ae88aa8, address of head: 0x7fff5ae88b00, \
value in walker: 0x7fff5ae88af0, value in head: 0x7fff5ae88af0, \
value pointed to by walker: 1525189360, value pointed to by head: 1
jeremy radcliff
  • 1,049
  • 3
  • 11
  • 27
  • `&walker` is not the address of the walker just `walker` is, as `walker` itself is a pointer! and you haven't really posted a [mcve]. You have similar issues elsewhere. also you are not showing `struct Node` chances are you have `value` as the first parameter in the struct, your code is all screwy you need to learn how *pointer syntax* works – Ahmed Masud Jan 01 '18 at 01:51
  • I think maybe we mean something different by walker. When I say "address of walker", I mean the address of the pointer itself, where the address of what it's pointing to is being held. I added the struct Node code, but I'm not sure what you mean about having "value" as the first parameter. Every LL implementation I've seen before has the data variable as the first parameter, and I think padding happens regardless in case that's what you were referring to. – jeremy radcliff Jan 01 '18 at 01:54
  • @AhmedMasud (contd). I don't think this justifies to ask to close. If this code is so unacceptable I'm not sure where I could ask for help with something like this. I understand how pointer syntax works. Both `head` and `walker` hold (point to) the same address but print different values when dereferenced using `*` notation, but print the same values when using the `->` notation. Honesly I'm pretty sure you didn't read my question carefully and jumped to conclusions in a frenzy to downvote somebody. – jeremy radcliff Jan 01 '18 at 01:59
  • I assure you, no one here is in any "frenzy" to downvote anyone. We spend our time to try and help fellow coders. However we do expect some courtesies by the OP that demonstrate an effort. The code snippet you posted is not [mcve] — i.e., someone cannot simply try to compile your code to figure out any compile-time or runtime issues. Given that the answer you accepted as valid solution would, simply pop out by turning on all warnings on any modern compiler. Something that you should do yourself anyhow. For gcc, it would be `gcc -Wall -Werror foo.c -c -o foo.o`. – Ahmed Masud Jan 01 '18 at 03:30
  • In any event, please understand that a downvote is not a personal attack on you. It's a statement about the question you posed. It invites you and incentivizes you to post a more cogent query. That exercise in itself, in many cases, tends to pop out the answer for the inquirer. Anyhow, I hope you will not take any downvotes personally, and understand that quality questions create useful answers. – Ahmed Masud Jan 01 '18 at 03:36
  • Next time: compile with all warnings enabled, and if in doubt, with `-Werror`. doesn't compile! – Antti Haapala -- Слава Україні Jan 01 '18 at 10:08

1 Answers1

4

In your printf argument list, the last two arguments are *walker and *head. These both have type struct Node, and of course they're being passed by value. There is no printf format specifier that will work on a struct Node, so you're getting garbage.

Try printing the value of one of the fields of the structure. For instance, you can pass walker->value and head->value, and change the format specifiers to %d to print int values.

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
  • Sorry, struct ListNode was my original name but I simplified to ask the question and forgot to change it there. – jeremy radcliff Jan 01 '18 at 02:02
  • The thing is that I also did try `walker->value` and `head->value` with `%d`, and in this case they do both print `1` as they should. But why is `*head` getting it right and not `*walker`? It seems unlikely that the `1` in `*head` is coincidently garbage of the value `1`. What I mean is that even though there's no format for structs in `printf`, I assumed the pointers point to the address of the first block of memory holding the struct, and therefore should print whatever is there if you specify the right format, in this case for an `int`. It worked for `head` but not for `walker`. – jeremy radcliff Jan 01 '18 at 02:04
  • @jeremyradcliff Because a `struct Node` probably takes more argument list space than `%p` expects. `printf` is expecting a pointer argument, but something incompatible is being passed. This results in `printf` getting out of sync with the argument list. That's why it's imperative that arguments match the types of the format speciers. – Tom Karzes Jan 01 '18 at 02:06
  • @jeremyradcliff using the wrong format specifier invokes undefined behavior. There’s no guarantee you’ll get consistent results when you do that. – dbush Jan 01 '18 at 02:08
  • @TomKarzes, Interesting, I just figured out what you were trying to say. I didn't know there was such a thing as argument list space. – jeremy radcliff Jan 01 '18 at 02:10
  • @dbush, I understand, but I'm interested in the way in which it's undefined. Everything is deterministic after all ultimately, so that behavior has to be traceable to something specific, like what Tom mentioned about argument list space. – jeremy radcliff Jan 01 '18 at 02:12
  • As explained, your code doesn't make any sense. The compiler tries to make sense of it, but there's nothing it can do that would be sensible because we really have no basis to expect anything in particular. – David Schwartz Jan 01 '18 at 02:15
  • @jeremyradcliff different compilers may handle arguments in different ways. One compiler may do things differently with different optimization settings. So you can’t depend on the results being reproducible. – dbush Jan 01 '18 at 02:15
  • It's *Undefined* because the C11-Standard says so [7.21.6.1 The fprintf function (2)](http://port70.net/~nsz/c/c11/n1570.html#7.21.6.1p2) – David C. Rankin Jan 01 '18 at 02:16
  • @jeremyradcliff When I say "argument list space", I just mean the amount of stack space an argument uses when passed to a function. For example, it stands to reason that a 4-byte integer will take less space than an 800-byte struct. In order to process its arguments, a function therefore needs to know exactly how they're passed, and how much space they consume. – Tom Karzes Jan 01 '18 at 02:16
  • @DavidSchwartz, I guess I was thinking/hoping that by dereferencing the memory address where the `int` variable of the struct is held (which should be the same as the address held by the pointer since it holds the first address block of structs and arrays, at least I think), and specifying an `int` format, the compiler would blindly go there expecting an `int` because of the `%d` and happen to find one there since that's what is stored at that address. – jeremy radcliff Jan 01 '18 at 02:20
  • @TomKarzes, I think your theory is right, because I tried again this time switching the order of `*head` and `*walker` in the argument list of `printf`, and the results were reversed, whereby `*head` now gave a weird long decimal value and `*walker` gave the `1` value held by the node. The only thing is that wouldn't you expect the first "too long" argument to mess up the sync with the argument list for the later argument? IOW, if the order is `*walker`, `*head` in the `printf` statement, shouldn't `*head` get messed up instead of, as it happens, `*walker` messing up and `head` getting the 1? – jeremy radcliff Jan 01 '18 at 02:27
  • @jeremyradcliff It's highly implementation-dependent. In many implementations, the stack grows from high to low. For instance, you may be getting `walker->next` as the first value and `walker->value` as the second, with `*head` being completely ignored. But that is highly speculative, and you can expect your results to vary from one implementation to another. – Tom Karzes Jan 01 '18 at 02:36
  • @TomKarzes, that makes sense, thanks for taking the time to explain all of this. – jeremy radcliff Jan 01 '18 at 02:39
  • @jeremyradcliff But `%d` is not a format specifier for an address, so it couldn't tell the compiler to go somewhere and expect an `int` at that address. So your expectation/hope was unrealistic and unjustified. – David Schwartz Jan 01 '18 at 03:22