0

4I am trying to get a pointer address from a pointer to a pointer array, however I just get garbage when I run the code below. How do I retrieve the pointer address of one of the char * from the char ** array? Thanks for checking this out.

Specifically, I want to obtain the address of "wh" via "what" and assign it to "hi".

char * hi;
char * wh;
char ** what;

int main(void) {
    char z[4] = "wx\0";
    char a[4] = "ab\0";
    hi = &z;
    wh = &a;
    what = (char **) malloc( 25 * sizeof(char));
    what[0] = &hi;
    what[1] = &wh;

    printf("%s | %s\n", hi, wh);

    hi = &what[1];

    printf("%s | %s\n", hi, wh);

    return EXIT_SUCCESS;
}
Castyr
  • 380
  • 3
  • 14
  • 1
    When you say "pointer address", do you mean the address of the pointer itself, or the address it's pointing to? – Peter Bloomfield Nov 01 '13 at 14:10
  • Sorry, I should have been more clear, the address it is pointing to. – Castyr Nov 01 '13 at 14:11
  • Thanks, I was under the impression the string terminator \0 was one character. I have updated the code accordingly. – Castyr Nov 01 '13 at 14:14
  • [Please don't cast the return value of `malloc()` in C](http://stackoverflow.com/a/605858/28169). Also your call is *very* strange. – unwind Nov 01 '13 at 14:15
  • 1
    When you call malloc, it returns a char*. Why are you casting it to char**? Also, call calloc(), not malloc(), for allocating contiguous memory chunks like "25 chars". – Zach Stark Nov 01 '13 at 14:15
  • @Sukminder: `z` and `a` are (were, before the edit) three bytes, because they are defined as arrays of three `char`. Initializing them with a string literal containing three explicit characters and one implicit null character is legal. The implicit terminating null is ignored. – Eric Postpischil Nov 01 '13 at 14:15
  • @Justin3o9 `'\0'` is indeed a single character, but you have `char z[4]` and that `4` won't be forgotten. – unwind Nov 01 '13 at 14:15
  • @EricPostpischil What? The arrays have `[4]`. – unwind Nov 01 '13 at 14:16
  • @unwind: The question was edited. – Eric Postpischil Nov 01 '13 at 14:17
  • @ZachStark Wrong, the return type of `malloc()` is `void *`. And of course the memory returned from `malloc()` is just as "contiguous" as that which `calloc()` returns. – unwind Nov 01 '13 at 14:18
  • @unwind My point still stands; it returns a single pointer rather than a double pointer that it is being explicitly cast to. – Zach Stark Nov 01 '13 at 14:19
  • @ZachStark That was hardly the way you stated it, though. :) There's a *huge* amount of confusion around here about the return type of `malloc()` and how to deal with `void *` in C, and making it worse is very counter-productive in my opinion. – unwind Nov 01 '13 at 14:25
  • @ZachStark, the return from malloc can converted to a pointer to any type, including a pointer type. Thus assigning the return from malloc to a `char **` is perfectly legitimate. The cast is unnecessary, however. – davmac Nov 01 '13 at 14:30

3 Answers3

3

Corrected code:

#include <stdio.h>
#include<stdlib.h>
char * hi;
char * wh;
char ** what;

int main(void) {
    char z[3] = "wx\0";
    char a[3] = "ab\0";
    hi = z;
    wh = a;
    what = malloc(2 * sizeof *what);
    what[0] = hi;
    what[1] = wh;

    printf("%s | %s\n", hi, wh);

    hi = what[1];

    printf("%s | %s\n", hi, wh);

    return 0;
}

The type of hi and wh is not the same as of &z and &a, even though they should yield the same value. Also you want what[1] in hi not the value of the memory location where it is. Also, in C you do not need to cast the return of malloc. However, in C++ the cast is required although its better to use the new operator.

Sadique
  • 22,572
  • 7
  • 65
  • 91
  • 1
    This `what = (char **) malloc( 25 * sizeof(char))` is broken, or at least misleading. So, the code is not yet "corrected". As usual, using type names under `sizeof` and casting result of `malloc` is a recipe for errors. Should be `what = malloc(25 * sizeof *what)`. – AnT stands with Russia Nov 01 '13 at 14:17
  • 2
    `malloc()` should be modified to allocate for `char *`'s – smRaj Nov 01 '13 at 14:17
  • 1
    I see that Acme has edited to the One True(TM) form of `malloc()`, great! – unwind Nov 01 '13 at 14:26
2

Pointer Assignment

  • hi and wh are defined as pointer to char. So, change your assignment statements

    from,

    hi = &z; /* Type of &z is pointer-to-array-of-4-char */
    wh = &a; /* Type of &a is pointer-to-array-of-4-char */
    

    to,

    hi = z; /* Type of z is pointer-to-char. Array name, here, decays into pointer 
               to first element of the array */
    wh = a; /* Type of a is pointer-to-char */
    

  • what is defined as type, pointer to pointer to char. So, change your malloc statement

    from,

    what = (char **) malloc( 25 * sizeof(char)); /* what needs to hold char*'s, 
                                                    you have allocated only for char's */
    

    to,

    what = malloc(25 * sizeof *what); /* what is of type char**. *what gives you char* */
    

  • Also, change your what , hi assignment statements

    from,

    what[0] = &hi; /* Type of what[0] is pointer-to-char;
                      Type of &hi is pointer-to-pointer-to-char */
    what[1] = &wh; /* Type of what[1] is pointer-to-char;
                      Type of &wh is pointer-to-pointer-to-char */
    ...
    hi = &what[1]; /* Type of hi is pointer-to-char;
                      Type of &what[1] is pointer-to-pointer-to-char */
    

    to ,

    what[0] = hi; /* Types are same */
    what[1] = wh; /* Types are same */
    ...
    hi = what[1]; /* Types are same */
    

Note: The size of what is too high than what really required for the posted program. If you feel, you are going to have the same program, modify 25 to 2 in the malloc.

smRaj
  • 1,246
  • 1
  • 9
  • 13
0
char * hi;
char * wh;
char ** what;

int main(void) {
    char z[4] = "wx\0";
    char a[4] = "ab\0";
    hi = &z;
    wh = &a;

First mistake; the types of the expressions &z and &a are both char (*)[4] (pointer to 4-element array of char), not char *. To fix this, drop the & from both:

    hi = z;
    wh = a;

Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression is the address of the first element in the array.

    what = (char **) malloc( 25 * sizeof(char));

Don't cast the result of malloc; it isn't necessary1, and depending on the compiler version it can suppress a useful diagnostic. You also have a type mismatch. You want to space for 25 pointers to char, but you're only allocating enough for 25 plain chars. Rewrite that as

    what = malloc( sizeof *what * 25 );

The type of the expression what is char **; thus, the type of the expression *what is char *. So sizeof *what will give you the same result as sizeof (char *). The above line allocates enough memory to store 25 pointers to char, and assigns the resulting pointer to what.

    what[0] = &hi;
    what[1] = &wh;

Again, drop the &; hi and wh are already pointers to char:

    what[0] = hi;
    what[1] = wh;

    printf("%s | %s\n", hi, wh);

    hi = &what[1];

Type mismatch; &what[1] has type char **, hi has type char *. Again, drop the &.

    hi = what[1];

hi and wh now point to the same thing (what[1] == wh and hi == what[1], so hi == wh; that is, both hi and wh contain the same pointer value).

    printf("%s | %s\n", hi, wh);

    return EXIT_SUCCESS;

}


1. In C, that is; C++ is a different story, but if you're writing C++, you shouldn't be using malloc anyway.
John Bode
  • 119,563
  • 19
  • 122
  • 198