char** function parameters

Discussion in 'C Programming' started by confusedcoder@hotmail.com, Jul 19, 2005.

  1. Guest

    Suppose I have the following function:

    void doSomething(char** array, int size);

    Normally, I would call the function with an array of, say, 3
    elements...

    char* strs[] = { "str1","str2","str3" };
    doSomething(strs, 3);

    That works fine. But if I want to pass it only one char*, I would
    think this would work....

    char* str = "str1";
    doSomething(&str, 1);

    It compiles with a warning about incompatible pointer types, and
    needless to say it doesn't behave as I expected. "str1" does not get
    passed into the function. What am I doing wrong? How can I pass a
    single char* into the function?
     
    , Jul 19, 2005
    #1
    1. Advertising

  2. On Tue, 19 Jul 2005 wrote:

    > Suppose I have the following function:
    >
    > void doSomething(char** array, int size);
    >
    > Normally, I would call the function with an array of, say, 3
    > elements...
    >
    > char* strs[] = { "str1","str2","str3" };
    > doSomething(strs, 3);
    >
    > That works fine. But if I want to pass it only one char*, I would
    > think this would work....
    >
    > char* str = "str1";
    > doSomething(&str, 1);
    >
    > It compiles with a warning about incompatible pointer types, and
    > needless to say it doesn't behave as I expected. "str1" does not get
    > passed into the function. What am I doing wrong? How can I pass a
    > single char* into the function?


    Here is a really simple program. There isn't a compilation problem :

    /* Compiled with gcc -Wall -pedantic -O3 */
    #include <stdio.h>
    #include <stdlib.h>

    void f(char **t)
    {
    printf("%s\n", *t);
    }

    int main(void)
    {
    char * str = "str0";
    char * tab[] = { "str1", "str2", "str3" };
    f(&str);
    f(tab);
    return EXIT_SUCCESS;
    }

    Everything goes fine.

    So my guess is you're having another kind of problem, which isn't directly
    related to passing your pointer.

    --
    "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
    que je veux !"
    "The obvious mathematical breakthrough would be development of an easy
    way to factor large prime numbers." (Bill Gates, The Road Ahead)
     
    Stephane Zuckerman, Jul 19, 2005
    #2
    1. Advertising

  3. wrote:
    > Suppose I have the following function:
    >
    > void doSomething(char** array, int size);
    >
    > Normally, I would call the function with an array of, say, 3
    > elements...
    >
    > char* strs[] = { "str1","str2","str3" };
    > doSomething(strs, 3);
    >
    > That works fine. But if I want to pass it only one char*, I would
    > think this would work....
    >
    > char* str = "str1";
    > doSomething(&str, 1);
    >
    > It compiles with a warning about incompatible pointer types, and
    > needless to say it doesn't behave as I expected. "str1" does not get
    > passed into the function. What am I doing wrong? How can I pass a
    > single char* into the function?


    I don't see anything wrong with what you posted, can you post a small
    but complete program that produces the warning when compiled, and what
    exactly is not behaving as you expected?

    Robert Gamble
     
    Robert Gamble, Jul 19, 2005
    #3
  4. Guest

    The problem was that I was treating a char[256] as a char*. Here is a
    modification of Stephane's program to demonstrate what I want to do:

    #include <stdio.h>
    #include <stdlib.h>

    void f(char **t)
    {
    printf("%s\n", *t);
    }

    int main(void)
    {
    char foo[256];
    strcpy(foo, "bar");

    f(&foo); /* WRONG */

    return EXIT_SUCCESS;
    }

    The gcc compiler warning is "assignment from incompatible pointer
    type," and what prints out when I run the program is garbage.

    So is it possible to pass the contents of foo[256] into the function
    f()?
     
    , Jul 19, 2005
    #4
  5. wrote:
    > The problem was that I was treating a char[256] as a char*. Here is a
    > modification of Stephane's program to demonstrate what I want to do:
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > void f(char **t)
    > {
    > printf("%s\n", *t);
    > }
    >
    > int main(void)
    > {
    > char foo[256];
    > strcpy(foo, "bar");


    you need to #include <string.h> for strcpy.

    > f(&foo); /* WRONG */


    Yes, that is wrong. f takes an argument of type pointer to pointer to
    char, you are passing pointer to char (foo and &foo decay into a
    pointer to the first element of the array, it is the same as &foo[0]).

    > return EXIT_SUCCESS;
    > }
    >
    > The gcc compiler warning is "assignment from incompatible pointer
    > type," and what prints out when I run the program is garbage.
    >
    > So is it possible to pass the contents of foo[256] into the function
    > f()?


    You can do this:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    void f(char **t)
    {
    printf("%s\n", *t);
    }
    int main(void)
    {
    char foo[256];
    char *ptr = foo;
    strcpy(foo, "bar");
    f(&ptr)
    return EXIT_SUCCESS;
    }

    Robert Gamble
     
    Robert Gamble, Jul 19, 2005
    #5
  6. Default User Guest

    Robert Gamble wrote:


    > > f(&foo); /* WRONG */

    >
    > Yes, that is wrong. f takes an argument of type pointer to pointer to
    > char, you are passing pointer to char (foo and &foo decay into a
    > pointer to the first element of the array, it is the same as &foo[0]).



    That's incorrect. &foo is a pointer to the array, so it has type
    pointer to array 256 of char, NOT pointer to char.




    Brian
     
    Default User, Jul 19, 2005
    #6
  7. Eric Sosman Guest

    Robert Gamble wrote:
    > wrote:
    >
    >>The problem was that I was treating a char[256] as a char*. Here is a
    >>modification of Stephane's program to demonstrate what I want to do:
    >>
    >>#include <stdio.h>
    >>#include <stdlib.h>
    >>
    >>void f(char **t)
    >>{
    >> printf("%s\n", *t);
    >>}
    >>
    >>int main(void)
    >>{
    >> char foo[256];
    >> strcpy(foo, "bar");

    >
    >
    > you need to #include <string.h> for strcpy.
    >
    >
    >> f(&foo); /* WRONG */

    >
    >
    > Yes, that is wrong. f takes an argument of type pointer to pointer to
    > char, you are passing pointer to char (foo and &foo decay into a
    > pointer to the first element of the array, it is the same as &foo[0]).


    No, no, no. Please see Question 6.12 in the comp.lang.c
    Frequently Asked Questions (FAQ) list

    http://www.eskimo.com/~scs/C-faq/top.html

    In particular,

    - Plain `foo' decays to a pointer to the array's first
    element, but `&foo' does not.

    - Plain `foo' is the same as `&foo[0]', but `&foo' is
    a different thing altogether.

    - A proper understanding of the type of `&foo' is the
    key to the O.P.'s question.

    --
     
    Eric Sosman, Jul 19, 2005
    #7
  8. John Bode Guest

    wrote:
    > The problem was that I was treating a char[256] as a char*. Here is a
    > modification of Stephane's program to demonstrate what I want to do:
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > void f(char **t)
    > {
    > printf("%s\n", *t);
    > }
    >
    > int main(void)
    > {
    > char foo[256];
    > strcpy(foo, "bar");
    >
    > f(&foo); /* WRONG */
    >


    Ah, enlightenment dawns. Try something like this:

    char *p = foo;
    f(&p);

    > return EXIT_SUCCESS;
    > }
    >
    > The gcc compiler warning is "assignment from incompatible pointer
    > type," and what prints out when I run the program is garbage.
    >


    Yes, because the type of &foo is char(*)[256], not char**.

    > So is it possible to pass the contents of foo[256] into the function
    > f()?


    Try the trick above, see if it helps.
     
    John Bode, Jul 19, 2005
    #8
  9. Default User wrote:
    > Robert Gamble wrote:
    >
    >
    > > > f(&foo); /* WRONG */

    > >
    > > Yes, that is wrong. f takes an argument of type pointer to pointer to
    > > char, you are passing pointer to char (foo and &foo decay into a
    > > pointer to the first element of the array, it is the same as &foo[0]).

    >
    >
    > That's incorrect. &foo is a pointer to the array, so it has type
    > pointer to array 256 of char, NOT pointer to char.


    Yup, thanks for the correction.

    Robert Gamble
     
    Robert Gamble, Jul 19, 2005
    #9
  10. Chris Torek Guest

    > wrote:
    [edited for space]
    >> void f(char **t) { printf("%s\n", *t); }
    >> int main(void) {
    >> char foo[256];
    >> strcpy(foo, "bar");
    >> f(&foo); /* WRONG */


    In article <>
    John Bode <> wrote:
    >Ah, enlightenment dawns. Try something like this:
    >
    > char *p = foo;
    > f(&p);


    Indeed. A picture might also help:

    foo:
    +-----+-----+-----+-----+-----...-----+
    | 'b' | 'a' | 'r' | 0 | (junk)... |
    +-----+-----+-----+-----+-----...-----+

    Here "foo" is an array of size 256 containing "char"s. Note that
    there *is no pointer*, there is just the array named "foo", which
    occupies 256 bytes.

    Inside f(), assuming that **t == 'k' and that the printf()
    will print (say) "k2":

    t:
    +----------------------+ +----------------------+
    | *------------------> | * |
    +----------------------+ +-----------|----------+
    /
    /
    /
    |
    v
    +-----+-----+-----+
    | 'k' | '2' | 0 |
    +-----+-----+-----+

    Here there are *two* pointers: t, and *t. In this illustration
    I drew them both as four bytes long (by making the boxes about
    four times the size of the one-byte "char" boxes), but they could
    be 2 or 3 or 4 or 8 or 128 bytes, or (on some rather unusual
    systems) even just one byte. The important item is that there
    are, and *must be*, two pointers -- the one named t, and one that
    t points to -- before you can use **t. (The call to printf()
    will access (*t)[0], aka **t, and then (*t)[1], and then (*t)[2],
    and so on.)

    Now, if you just use "foo" in a value context (or write &foo[0]),
    the compiler will *construct* a pointer value, pointing to the
    first element of the array:

    foo:
    +-----+-----+-----+-----+-...-+
    *------> | 'b' | 'a' | 'r' | 0 | ... |
    +-----+-----+-----+-----+-...-+

    but this pointer is not (necessarily) stored in memory anywhere,
    as it is a mere value, not an object. By adding "char *p = foo",
    we create an actual object, so now the above becomes:

    p: foo:
    +----------+ +-----+-----+-----+-----+-...-+
    | *------> | 'b' | 'a' | 'r' | 0 | ... |
    +----------+ +-----+-----+-----+-----+-...-+

    Now if we call f(&p), we pass to f() a value pointing to the pointer
    named "p". f()'s first actions, even before any code inside f()
    gets excuted, are to copy that value into an object, the one we
    named "t" in f(). In other words, function parameters are really
    just ordinary local variables, initialized "by magic" as we begin
    executing the function, using the values passed in from the caller.
    So now we have "t" (in f()) pointing to "p" (in the main() that I
    snipped) pointing to &foo[0] (also in main()), so now the picture
    we *wanted* -- t pointing to a pointer that points to the first of
    a series of "char"s -- is in fact the picture we *have*.

    Whenever you (the generic "you") are struggling with pointers, it
    can help to draw pictures. Each named object (variable) is a box
    containing a value, or junk if it is uninitialized. If the type
    of the object is "pointer to ...", the object contains an arrow.
    You need to make sure the arrow points in turn to some other thing
    somewhere in memory -- another named object, or perhaps memory
    obtained from malloc(). Each chunk of memory in turn contains a
    value (or junk), and if the type it is meant to contain is "pointer
    to ...", the value is an arrow -- and you have to make the arrow
    point somewhere useful, just like last time. You can use a pointer
    to write to the thing to which the pointer points, so one
    arrow pointing to the first of several uninitialized-memory arrows
    can be used to initialize them:

    T **ptr = malloc(2 * sizeof *ptr);

    produces (assuming malloc() succeeds) this picture:

    (pointing off into the weeds)
    ptr: /
    +---------+ +----/---+---------+
    | *---------------> | * | * |
    +---------+ +--------+-----\---+
    \ (more weeds)

    and now you can say "ptr[0] = (some expression)" to set ptr[0],
    and likewise with ptr[1]. As before, you can point them to
    named variables (of type T), or call malloc() again. The
    important thing is to make them point somewhere, and be sure
    they still point somewhere valid whenever you use them.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Jul 20, 2005
    #10
  11. Rajan Guest

    Primarily what you need to do is to avoid the warning you need to
    typecast
    by doing doSomething((char **)&str,1);
    So let's say your function is

    void doSomething(char** s, int size)
    {
    printf("%s\n",*s);
    }
    This needs to be done because you are not printing s[0], instead are
    trying to print address of s[0];
    Remember this is a double pointer.
     
    Rajan, Jul 20, 2005
    #11
  12. > Primarily what you need to do is to avoid the warning you need to
    > typecast
    > by doing doSomething((char **)&str,1);


    I'm not sure I'm understanding why you would have to absolutely try to
    hush the compiler. Warnings are there for a good reason, most of the time.
    The only thing we need to know is "is this warning announcing something
    that was unexpected ?"... well, IMO at least :)

    --
    "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
    que je veux !"
    "The obvious mathematical breakthrough would be development of an easy
    way to factor large prime numbers." (Bill Gates, The Road Ahead)
     
    Stephane Zuckerman, Jul 20, 2005
    #12
  13. Guest

    Thanks for all the feedback!
     
    , Jul 22, 2005
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    8
    Views:
    561
    Bryan Donlan
    Aug 26, 2005
  2. lovecreatesbeauty
    Replies:
    1
    Views:
    1,149
    Ian Collins
    May 9, 2006
  3. Virtual_X
    Replies:
    16
    Views:
    582
    Default User
    Jul 14, 2007
  4. Daracne
    Replies:
    4
    Views:
    350
    Default User
    Jul 20, 2007
  5. bintom
    Replies:
    10
    Views:
    725
    Paul Bibbings
    Jun 27, 2010
Loading...

Share This Page