Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 5 of 5
  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    16
    Thanks
    0
    Thanked 0 Times in 0 Posts

    C arrays and pointers etc. Help!

    I have the code

    int k = 2;
    int a[10];
    int b = 0;

    for(b=0;b<10;b++)
    {
    a[b] = 2;
    }

    printf("Normally with a[k] we get %d\n", a[k]);

    int c;

    c = *(int *) ((int)&a[0] + k*sizeof(int));

    printf("So c = %d\n", c);


    Where I'm just printing out a value from the array "a". However, I don't get why

    c = *(int *) ((int)&a[0] + k*sizeof(int));

    works.

    I've been told

    *(int *) = indirect
    (int)&a[0] = base address
    k*sizeof(int) = offset

    I know that the end bit selects which value in the array I want (how many objects away from the start of the array the thing I want is), but I don't get what the other two parts do.

    Thanks

  • #2
    Regular Coder ralph l mayo's Avatar
    Join Date
    Nov 2005
    Posts
    951
    Thanks
    1
    Thanked 31 Times in 29 Posts
    Code:
    c = *(int *) ((int)&a[0] + k*sizeof(int));
    is invalid because (int)&a[0] casts int* to int. While technically possible, this is a Bad Idea(tm) for a few reasons, not least of which that it's completely unnecessary and that it breaks on 64-bit systems because the address doesn't fit in an int.

    So, after a bare minimum of sanity checking you have:
    Code:
    c = *(int *) ((int*)&a[0] + k*sizeof(int));
    But, a[0] is already an int, per the definition of a as an array of integers, therefore &a[0] is already an int*, and the innermost cast is redundant.
    Code:
    c= *(int *) (&a[0] + k*sizeof(int));
    In C arrays, the subscript it just a memory offset. What the interesting part of this code is doing is duplicating its functionality by manually calculating the offset the compiler would normally figure out for you with the a[k] form. int[] a is the same thing as int* a, both are simply pointers to an integer. Arrays only extend the concept a bit by letting the compiler know there are more integers pointed to after the first.
    Furthermore, &a[0] is always equal to a, because a[0] doesn't offset any from the starting position pointed to by a itself.
    Code:
    c = *(int *) (a + k*sizeof(int));
    The k * sizeof(int) part, like I said, duplicates the actual subscripting operation. When the compiler lays out an array of ints, it puts each exactly an int-length away from the previous value in a contiguous block of memory so that they fit in the smallest possible space. As a side-benefit of this implementation detail, you know that the nth int of a is always n * sizeof(int) away from a[0]. It is just an implementation detail though, you shouldn't lean on it too heavily, especially since the subscript notation is so much nicer.

    Finally, the type of (a + sizeof(int)) is already int* so the outer cast to int* turns out to be redundant as well.
    Code:
    *(a + k * sizeof(int)) == a[k]
    Ends up being one of the basic axioms of C arrays.

  • #3
    Registered User
    Join Date
    May 2006
    Posts
    16
    Thanks
    0
    Thanked 0 Times in 0 Posts
    So I get that

    Code:
    ((int)&a[0] + k*sizeof(int))
    is the memory address of the object k in my array. However, I'm not too sure what some of the other parts do (my C skills could be described as "developing" at best)

    If I have

    Code:
    (int*)&a[0]
    What does the (int) or (int*) actually mean/do? When you talked about using (int) and that the address doesn't fit in an int what does that mean?

    Also with

    Code:
    *(int *)
    What does the first * do and what does the (int *) do? (I guess it means something along the lines of "grab the int value from [this] memory address", but what does each piece of code do in programming terms?)

    Thanks

  • #4
    Rockstar Coder
    Join Date
    Jun 2002
    Location
    USA
    Posts
    9,074
    Thanks
    1
    Thanked 328 Times in 324 Posts
    Quote Originally Posted by Advancedkill View Post
    If I have

    Code:
    (int*)&a[0]
    What does the (int) or (int*) actually mean/do? When you talked about using (int) and that the address doesn't fit in an int what does that mean?
    The (int *) is a type cast and as said previously a completely unnecessary one. The data type of &a[0] is already going to be int* since a is an int array and & means the address of and a[0] means the first integer in array zero.
    OracleGuy

  • #5
    Regular Coder ralph l mayo's Avatar
    Join Date
    Nov 2005
    Posts
    951
    Thanks
    1
    Thanked 31 Times in 29 Posts
    Regarding the 64-bit thing, that was kind of regrettably off-topic, just please take away that you should not cast a pointer to an integer.

    The specific problem I was talking about was that on 64-bit systems memory addresses are 64 bits while int values may still be the standard 32 bits. Therefore, when you try to cram the larger value into the smaller you lose precision. I tried to compile the code you posted and gcc complained about it. I was just relaying its dismay, but in general if you're treating pointers to memory as integers, portability to systems with different architectures is near the least of your problems, because you're doing something fundamentally bizarre.

    My intuition says that the code you posted initially was written by someone who had a vague idea about how pointer arithmetic works but that didn't really understand it either. They added casts to force it work step-by-step and then ended up with some redundancy in the end.

    Offsetting memory "the long way" to get elements of an array isn't a useful idiom anyway, so probably the best take-away from this question is that if you are explicitly casting something you should stop and give some thought to what you're doing. By complaining about type errors, the compiler is trying to warn you that you're probably doing something stupid by, say, using an int* as an int. Just because you can shut it up easily with the cast doesn't mean you should.

    If I have

    Code:
    (int*)&a[0]
    What does the (int) or (int*) actually mean/do? When you talked about using (int) and that the address doesn't fit in an int what does that mean?
    a[0] says get the 0th element of a.
    &(previous result) says get the address the value (previous result) is stored at.
    (int*)(previous result) is a message to the compiler that says "pretend like this is a pointer to an integer". In this case it's easy, safe, and redundant because the address of a[0], an int, is an int*.

    Sometimes when a piece of memory goes through some contortions the compiler can't surmise what the memory really represents. Casting is a "reminder".

    Code:
    *(int *)
    What does the first * do and what does the (int *) do? (I guess it means something along the lines of "grab the int value from [this] memory address", but what does each piece of code do in programming terms?)
    The first * is an operator that means dereference. The thing it's attached to should be a pointer, because it makes that thing take on its real value instead of an address pointing to the real value. It's the exact opposite of &, the address-of operator, aka reference.

    Referencing with & is the act of taking the address of a value, dereferencing with * is the act of taking the value of an address.

    (int*) is a type-cast to a pointer to integer. It means that whatever is to the right is to be interpreted as a pointer to an integer no matter what the compiler thinks it is. Like I said before it's not needed at all in this case because the compiler has proof that the right operand is already a pointer to an integer anyway.
    Last edited by ralph l mayo; 07-23-2008 at 07:53 AM.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •