help passing pointer to char array as argument

Discussion in 'C++' started by rob.kirkpatrick@telefonica.net, Jul 5, 2006.

  1. Guest

    Hello

    I need to populate an array of char arrays at run-time. A very
    simplifed version of the code is below.

    char ** list should contain cnt char arrays. The values of char ** list
    are set by the function foo(). A pointer to char ** list is passed to
    foo() as an argument.

    The problem is that when foo() returns, char ** list contains rubbish
    and does not always contain cnt char arrays. Can anyone tell me what
    I'm doing wrong? Note that I don't want to use the vector or string for
    efficiency. Note that the code that get the time has nothing to do with
    the real programme. It's just a simplification for the purpose of this
    posting.


    (I have noticed that if the values are constant char arrays there is no
    problem)

    //*********************************************************************************
    #include <iostream.h>
    #include <time.h>
    #include <string.h>
    #include <stdlib.h>

    void foo(char *** array, int cnt){

    char buf[256];

    for(int i=0; i<cnt; i++){
    long t = time(NULL); // just for demonstration
    itoa(t, buf, 10);
    (*array) = buf;
    cout << i << " " << (*array) << '\n';
    }
    }

    int main(int argc, char ** argv){

    int cnt = 10;
    char ** list = new char*[10];

    foo(&list, cnt);

    for(int i=0; i<cnt; i++){
    cout << i << " " << list << "\n";
    }

    delete [] list;

    return 0;
    }
    //*********************************************************************************

    Thanks!!!!!
    , Jul 5, 2006
    #1
    1. Advertising

  2. Tim Love Guest

    writes:

    >void foo(char *** array, int cnt){


    > char buf[256];

    This fixes the value of buf for the duration of the function, so

    > (*array) = buf;

    will set all the elements to the same value - the value of buf.

    Also, buf is a local variable, so when foo ends, the space used by buf can be recycled.

    The short answer to your question is to reconsider using containers.
    Tim Love, Jul 5, 2006
    #2
    1. Advertising

  3. wrote:
    > Hello
    >
    >
    > void foo(char *** array, int cnt){
    >
    > char buf[256];
    >
    > for(int i=0; i<cnt; i++){
    > long t = time(NULL); // just for demonstration
    > itoa(t, buf, 10);
    > (*array) = buf;
    > cout << i << " " << (*array) << '\n';
    > }
    > }
    >


    For starters, you're assigning the same local buffer 'buf' multiple
    times, then that's going out of scope at the end of the function.
    No offence mate, but you're clearly struggling juggling three levels of
    indirection; you're going to be a lot better off using std::vector and
    std::string. They are designed precisely to allow programmers to avoid
    these sorts of gymnastics and pitfalls. Your concerns about
    "performance" are misplaced, get the thing working in a clear and
    understandable way and then worry about tweaking it for performance
    *if* you need to. Which you won't.
    tragomaskhalos, Jul 5, 2006
    #3
  4. Ian Collins Guest

    wrote:
    > Hello
    >
    > I need to populate an array of char arrays at run-time. A very
    > simplifed version of the code is below.
    >
    > char ** list should contain cnt char arrays. The values of char ** list
    > are set by the function foo(). A pointer to char ** list is passed to
    > foo() as an argument.
    >
    > The problem is that when foo() returns, char ** list contains rubbish
    > and does not always contain cnt char arrays. Can anyone tell me what
    > I'm doing wrong? Note that I don't want to use the vector or string for
    > efficiency. Note that the code that get the time has nothing to do with
    > the real programme. It's just a simplification for the purpose of this
    > posting.
    >

    Why not just use std::vector<std::string> and save yourself a lot of
    trouble?

    --
    Ian Collins.
    Ian Collins, Jul 5, 2006
    #4
  5. Guest

    Tim Love wrote:
    > writes:
    >
    > >void foo(char *** array, int cnt){

    >
    > > char buf[256];

    > This fixes the value of buf for the duration of the function, so
    >
    > > (*array) = buf;

    > will set all the elements to the same value - the value of buf.
    >
    > Also, buf is a local variable, so when foo ends, the space used by buf can be recycled.
    >
    > The short answer to your question is to reconsider using containers.


    Thanks, Tim.
    I might be wrong but I'm using a pointer to char ** list and assigning
    the value of buf. char ** list's values should persist after foo()
    returns. Isn't that right? Thanks!!!

    Rob
    , Jul 5, 2006
    #5
  6. Tim Love Guest

    writes:

    >Thanks, Tim.
    >I might be wrong but I'm using a pointer to char ** list and assigning
    >the value of buf. char ** list's values should persist after foo()
    >returns. Isn't that right?

    But what persists is just a pointer. It's pointing to memory that's being
    rewritten then freed, so it's not a useful pointer.

    http://burks.bton.ac.uk/burks/language/c/ptrtut/pointers.htm may help,
    but vectors+strings are a safer bet.
    Tim Love, Jul 5, 2006
    #6
  7. TB Guest

    skrev:
    > Tim Love wrote:
    >> writes:
    >>
    >>> void foo(char *** array, int cnt){
    >>> char buf[256];

    >> This fixes the value of buf for the duration of the function, so
    >>
    >>> (*array) = buf;

    >> will set all the elements to the same value - the value of buf.
    >>
    >> Also, buf is a local variable, so when foo ends, the space used by buf can be recycled.
    >>
    >> The short answer to your question is to reconsider using containers.

    >
    > Thanks, Tim.
    > I might be wrong but I'm using a pointer to char ** list and assigning
    > the value of buf. char ** list's values should persist after foo()
    > returns. Isn't that right? Thanks!!!


    You're assigning the address of 'buf' to each pointer, and 'buf' only
    exists within the scope of 'foo()', not outside in 'main()'. The address
    points to some location on the stack, which is recycled and overwritten
    by subsequent stack operations, like the following call to
    std::basic_ostream::eek:perator<<(...).

    You need to allocate the buffer with 'new' if you want it to persist,
    or dismiss any thoughts of efficiency and do as others have replied,
    skip deep indirection and use the provided framework of containers.

    For example:

    #include <sstream>
    #include <vector>
    #include <string>
    #include <ctime>
    #include <ostream>
    #include <algorithms>

    void foo(std::vector<std::string> &v, unsigned cnt) {
    std::eek:stringstream strm;
    for(unsigned i = 0; i < cnt; ++i) {
    strm << std::time(0);
    v.push_back(strm.str());
    strm.str("");
    }
    }

    int main(int argc, char* argv[])
    {
    std::vector<std::string> v;
    foo(v,10);
    std::copy(v.begin(),
    v.end(),
    std::eek:stream_iterator<std::string>(std::cout,"\n"));
    return 0;
    }

    --
    TB @ SWEDEN
    TB, Jul 5, 2006
    #7
  8. Guest

    TB wrote:

    >
    > You're assigning the address of 'buf' to each pointer, and 'buf' only
    > exists within the scope of 'foo()', not outside in 'main()'. The address
    > points to some location on the stack, which is recycled and overwritten
    > by subsequent stack operations, like the following call to
    > std::basic_ostream::eek:perator<<(...).
    >
    > You need to allocate the buffer with 'new' if you want it to persist,
    > or dismiss any thoughts of efficiency and do as others have replied,
    > skip deep indirection and use the provided framework of containers.
    >
    > TB @ SWEDEN


    Thanks to you and others who have got back to me. I'll take this
    advice; but I'm still curious as to the following:

    Essentially: is it possible to manipulate the values an array of chars
    from within the scope of a function so that they persist?

    foo(char *** list){
    // manipulate list elements
    }

    I assume if I allocate memory with "new", for example...

    (*array) = new char[256];

    ....how can I then free the memory? I assume "delete [] list" won't do
    it.

    Thanks!!!
    Rob
    , Jul 5, 2006
    #8
  9. TB Guest

    skrev:
    > TB wrote:
    >
    >> You're assigning the address of 'buf' to each pointer, and 'buf' only
    >> exists within the scope of 'foo()', not outside in 'main()'. The address
    >> points to some location on the stack, which is recycled and overwritten
    >> by subsequent stack operations, like the following call to
    >> std::basic_ostream::eek:perator<<(...).
    >>
    >> You need to allocate the buffer with 'new' if you want it to persist,
    >> or dismiss any thoughts of efficiency and do as others have replied,
    >> skip deep indirection and use the provided framework of containers.
    >>
    >> TB @ SWEDEN

    >
    > Thanks to you and others who have got back to me. I'll take this
    > advice; but I'm still curious as to the following:
    >
    > Essentially: is it possible to manipulate the values an array of chars
    > from within the scope of a function so that they persist?
    >
    > foo(char *** list){
    > // manipulate list elements
    > }
    >
    > I assume if I allocate memory with "new", for example...
    >
    > (*array) = new char[256];
    >
    > ...how can I then free the memory? I assume "delete [] list" won't do
    > it.
    >


    #include <iostream>
    #include <ctime>
    #include <cstdlib>

    void foo(char **& array, unsigned cnt){
    for(unsigned i = 0; i < cnt; ++i){
    char * buf = new char[256];
    long t = std::time(0);
    std::itoa(t, buf, 10);
    array = buf;
    std::cout << i << " " << array << std::endl;
    }
    }

    int main(int argc, char ** argv){
    unsigned cnt = 10;
    char ** list = new char*[10];

    foo(list, cnt);

    for(unsigned i = 0; i < cnt; ++i) {
    std::cout << i << " " << list << std::endl;
    }

    for(unsigned i = 0; i < cnt; ++i) {
    delete[] list;
    }
    delete[] list;

    return 0;
    }

    --
    TB @ SWEDEN
    TB, Jul 5, 2006
    #9
  10. Guest


    > #include <iostream>
    > #include <ctime>
    > #include <cstdlib>
    >
    > void foo(char **& array, unsigned cnt){
    > for(unsigned i = 0; i < cnt; ++i){
    > char * buf = new char[256];
    > long t = std::time(0);
    > std::itoa(t, buf, 10);
    > array = buf;
    > std::cout << i << " " << array << std::endl;
    > }
    > }
    >
    > int main(int argc, char ** argv){
    > unsigned cnt = 10;
    > char ** list = new char*[10];
    >
    > foo(list, cnt);
    >
    > for(unsigned i = 0; i < cnt; ++i) {
    > std::cout << i << " " << list << std::endl;
    > }
    >
    > for(unsigned i = 0; i < cnt; ++i) {
    > delete[] list;
    > }
    > delete[] list;
    >
    > return 0;
    > }
    >
    > --
    > TB @ SWEDEN


    Thanks very much TB!!!

    Rob
    , Jul 5, 2006
    #10
    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. lovecreatesbeauty
    Replies:
    1
    Views:
    1,043
    Ian Collins
    May 9, 2006
  2. Vijai Kalyan
    Replies:
    4
    Views:
    704
    Vijai Kalyan
    Nov 8, 2005
  3. Replies:
    3
    Views:
    731
  4. davidb
    Replies:
    0
    Views:
    761
    davidb
    Sep 1, 2006
  5. davidb
    Replies:
    6
    Views:
    1,547
    Default User
    Sep 1, 2006
Loading...

Share This Page