How does one code something like this?

Discussion in 'C Programming' started by Daniel Rudy, Jan 2, 2006.

  1. Daniel Rudy

    Daniel Rudy Guest

    Hello,

    I have a peice of code that I'm making an attempt to code. The problem
    is that I need to return an arbitrary number of char strings.

    int function(char *fname, int *dcount, char *data[])

    Would this work? If so, then how to you load the data into data? Malloc?


    --
    Daniel Rudy

    Email address has been base64 encoded to reduce spam
    Decode email address using b64decode or uudecode -m

    Why geeks like computers: look chat date touch grep make unzip
    strip view finger mount fcsk more fcsk yes spray umount sleep
    Daniel Rudy, Jan 2, 2006
    #1
    1. Advertising

  2. Daniel Rudy

    WaJo Guest

    Hi,

    I guess data should be declared like this Char ** data,
    yes, malloc will do it...

    Regards,
    WaJo, Jan 2, 2006
    #2
    1. Advertising

  3. Daniel Rudy a écrit :
    > I have a peice of code that I'm making an attempt to code. The problem
    > is that I need to return an arbitrary number of char strings.
    >
    > int function(char *fname, int *dcount, char *data[])
    >
    > Would this work?


    Nope.

    char **function(char const *fname, int *dcount)

    or better

    struct data
    {
    size_t count;
    char **arr;
    };

    int function (char const *fname, struct data *p_data)

    --
    A+

    Emmanuel Delahaye
    Emmanuel Delahaye, Jan 2, 2006
    #3
  4. Daniel Rudy

    Malcolm Guest

    "Daniel Rudy" <> wrote
    > I have a peice of code that I'm making an attempt to code. The problem
    > is that I need to return an arbitrary number of char strings.
    >
    > int function(char *fname, int *dcount, char *data[])
    >
    > Would this work? If so, then how to you load the data into data? Malloc?
    >

    You can't do it that way.
    The reason is that you don't know how many strings you have. Therefore you
    need to call

    char **ptr;
    int N; / *set to number of strings */
    ptr = malloc(N * sizeof(char *));

    (in fact you would probably malloc() 1 and then call realloc() as you add
    strings to the list, but that's just a detail).

    The pointer therefore changes, so you can't pass it it. You need a char ***,
    if you want to return it as a parameter.
    A triple pointer is getting messy, so it's probably better to return the
    pointer

    char **function(char *fname, int *dcount)
    Malcolm, Jan 2, 2006
    #4
  5. Daniel Rudy

    Daniel Rudy Guest

    At about the time of 1/2/2006 2:26 PM, Malcolm stated the following:
    > "Daniel Rudy" <> wrote
    >
    >>I have a peice of code that I'm making an attempt to code. The problem
    >>is that I need to return an arbitrary number of char strings.
    >>
    >>int function(char *fname, int *dcount, char *data[])
    >>
    >>Would this work? If so, then how to you load the data into data? Malloc?
    >>

    >
    > You can't do it that way.
    > The reason is that you don't know how many strings you have. Therefore you
    > need to call
    >
    > char **ptr;
    > int N; / *set to number of strings */
    > ptr = malloc(N * sizeof(char *));
    >
    > (in fact you would probably malloc() 1 and then call realloc() as you add
    > strings to the list, but that's just a detail).
    >
    > The pointer therefore changes, so you can't pass it it. You need a char ***,
    > if you want to return it as a parameter.
    > A triple pointer is getting messy, so it's probably better to return the
    > pointer
    >
    > char **function(char *fname, int *dcount)
    >
    >


    I'm having trouble visualizing this. I thought that char **ptr is a
    pointer to a pointer to a char (or array of chars). Am I wrong? I know
    that it can be done, look at int main(int argc, char *argv[]) which
    everyone knows. Hmm... I'm going to abandon this method and try
    something else, which may also result in another post on declaring
    nested unions and structures.

    --
    Daniel Rudy

    Email address has been base64 encoded to reduce spam
    Decode email address using b64decode or uudecode -m

    Why geeks like computers: look chat date touch grep make unzip
    strip view finger mount fcsk more fcsk yes spray umount sleep
    Daniel Rudy, Jan 2, 2006
    #5
  6. Daniel Rudy

    Malcolm Guest

    "Daniel Rudy" <> wrote
    > I'm having trouble visualizing this. I thought that char **ptr is a
    > pointer to a pointer to a char (or array of chars). Am I wrong? I know
    > that it can be done, look at int main(int argc, char *argv[]) which
    > everyone knows. Hmm... I'm going to abandon this method and try
    > something else, which may also result in another post on declaring
    > nested unions and structures.
    >

    A pointer can point to anything.

    If it points to an integer it is an int *, if it points to a character it is
    a char *.
    It can also point to another pointer. So a pointer to a pointer that points
    to a character would be a char **. A pointer to that would be a char ***,
    and so on (in practise you harldy ever need more than three levels).

    In C, you work with arrays of values by pointing to the first element. So if
    we have three integer in memory

    12 15 -4

    We can set a pointer, call it ptr, to point to the 12.

    *ptr gives us the 12
    *(ptr +1) gives us the 15
    *(ptr +2) gives us the -4.

    We can also use array notation

    ptr[0] is exactly the same a *ptr
    ptr[1] is exactly the same as (*ptr+1)

    This is especially useful for strings, because we generally don't know how
    long they will be. So you simply point to the first character in memory

    a s t r i n g 0

    we point to the 'a', and then we can examine all the other characters. The 0
    tells us where the string ends.
    Malcolm, Jan 3, 2006
    #6
  7. "Malcolm" <> writes:
    [...]
    > We can also use array notation
    >
    > ptr[0] is exactly the same a *ptr
    > ptr[1] is exactly the same as (*ptr+1)


    Quibble: ptr[1] is the same as *(ptr+1).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jan 3, 2006
    #7
  8. Hi, I think you're mostly right, but you wrote it in a way, that
    could easily be mis-interpreted, especially by someone who
    needs to have this explained ...

    Malcolm <> schrieb:

    > A pointer can point to anything.


    Better: Pointers can point to any type of object in memory.
    You can't point it to, say, the controller of your hard disk
    ;-)

    > If it points to an integer it is an int *, if it points to a character it is
    > a char *.


    To further clarify, this does *not* mean that an int pointer
    that accidentally points to a char object suddenly changes
    its type from int* to char*. An int* is an int* and will remain
    an int* as long as the program is running.

    An expample:

    struct { char str[10]; int i[10];} array;
    char *pc = &array.str[9]; // takes the address of the last element in str
    int *pi = &array.i; // address of the first (zero'th) element in i

    Now incrementing pc like in:

    pc = pc + 1;

    does not change the type of the pointer. pc is still a char*
    and when you try to do something with it, you get undefined
    behaviour. The operation to increment a pointer to one place
    _behind_ the last element of an array is perfectly legal and
    well defined.

    On the other hand:

    pi = pi - 1;

    does not change the type of pi from int* to char*, in fact
    (even if it were allowed and defined what to do when you de-
    crement a pointer to a place before the beginning of an array,
    which it isn't) does not even point to str[9] but probably
    to str[7]. In real life it can point anywhere, because of
    padding bytes the compiler puts between the end of str[] and
    the beginning of i[] to ensure that the elements contained
    in i[] can be accessed (some systems cannot access integers
    that reside on odd adresses, some can but extremely slow,
    some will cause bus errors or protection faults, ....
    it's undefined, _anything_ can happen).

    > It can also point to another pointer.


    Additionally, a void* can point to _any_ type of object.
    But that's about all that a void* can, or what you can
    do with a void*. a void* can point to a void** (can it?)
    but I have yet to discover of what use a void** could be.

    Before you use it for something more trivial than just
    pointing around, e.g. dereferencing it to access the object
    it points to, you have to cast it to a pointer of a
    particular type, meaning that _you_ have to know the type
    of object it points to. The compiler cannot do that, it
    relies on your knowing what you are doing. On some systems
    (especially embedded controllers) this can be used for
    some nasty tricks, but in 'standard' C this leads to
    undefined behaviour.

    The advantage of void* is that they can be
    casted to any other type and the accesses made via the casted
    (and therefore typed) pointer are guaranteed to succed in re-
    retrieving a porperly typed object at the location it points
    to. If you point a void* to the address of str[1] in the above
    struct of my 'example' and then cast it to an int*, you'll
    get undefined behaviour on most modern systems where
    sizeof(char) != sizeof(int). The result of this misaligned
    pointing is undefined, it you do nothing more than point
    to objects which, on a particular system, cannot be stored
    at this location nothing serious will happen, but if you
    try to access the misaligned object, your program will
    most certainly some kind of access error that will crash
    your program.

    to cast a void* to some other type of pointer, in C you
    do not need the explicit cast like

    int i;
    void* pv=&i;
    int *pi=(int*)pv;

    it is sufficient to just write:

    int *pi = pv;

    The compiler selflessly does the conversion itself ('implicit'
    cast).

    > *ptr gives us the 12
    > *(ptr +1) gives us the 15
    > *(ptr +2) gives us the -4.


    Note that we increment the pointer by the number of objects.

    The compiler knows their size and appropriately ensures that
    the increment in memory locations is correct.
    This is the reason why one can't do pointer-arithmetic
    with void* pointers, because the objects the pointer points
    to have no known type.
    You can add pointers and integers, but not pointers and
    pointers. With one exception: if both pointers are of the
    same type (e.g. int*) and both point to locations inside
    an int-array (up to one position after the last element
    of the array) you can use p2-p1 to get the number of
    elements between p1 and p2.

    > We can also use array notation
    >
    > ptr[0] is exactly the same a *ptr
    > ptr[1] is exactly the same as (*ptr+1)


    Typo: ptr[1] == *(ptr+1)

    > This is especially useful for strings, because we generally don't know how
    > long they will be.


    Which is one of the reasons why one shouldn't use functions like
    gets() or strcpy().
    Oops, different thread. ;-)

    > a s t r i n g 0


    better: "astring\0"

    > we point to the 'a', and then we can examine all the other characters. The 0
    > tells us where the string ends.


    Markus, hoping that I didn't make too much mistakes at this
    early time of day...
    Markus Becker, Jan 3, 2006
    #8
    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. Sunner Sun
    Replies:
    23
    Views:
    9,376
    Dan Pop
    Apr 13, 2004
  2. Diego Martins
    Replies:
    5
    Views:
    474
    Diego Martins
    Sep 5, 2006
  3. levon
    Replies:
    1
    Views:
    127
    Tony Bukres
    Jun 27, 2005
  4. Replies:
    9
    Views:
    148
  5. dmitrey
    Replies:
    5
    Views:
    398
    Jussi Piitulainen
    Apr 20, 2012
Loading...

Share This Page