Array of strings

Discussion in 'C Programming' started by jesper, May 13, 2005.

  1. jesper

    jesper Guest

    Hello,

    I have to load strings from a datbase and put them into an array.
    I get them by packets of 100 strings of 50 characters.
    Then I should do something like that : StringArray[x*100][50]
    But x can be huge, then I must allocate it dynamically.

    I have searched on Google, but I only found different solutions (malloc,
    realloc, calloc, ...)
    What could be the best solution ?

    Thanks in advance.
    jesper, May 13, 2005
    #1
    1. Advertising

  2. jesper

    Achintya Guest

    Hi,

    Hoping that you can use STLs in your set-up...one solution can be....

    list<vector<string> >

    string to store the 50 character string
    vector<> to store 100 such strings and
    list<> to store the packets...

    Hope you the know the usage of STLs....

    If you use STL you can be least bothered about the memory allocation
    and deallocation.

    -vs_p...
    Achintya, May 13, 2005
    #2
    1. Advertising

  3. jesper

    -berlin.de Guest

    jesper <> wrote:
    > I have to load strings from a datbase and put them into an array.
    > I get them by packets of 100 strings of 50 characters.
    > Then I should do something like that : StringArray[x*100][50]
    > But x can be huge, then I must allocate it dynamically.


    Rather likely, especially if you don't know in advance how many
    strings you're going to get, which wouldn't be unusal when dealing
    with databases.

    > I have searched on Google, but I only found different solutions (malloc,
    > realloc, calloc, ...)
    > What could be the best solution ?


    They are not mutually exclussive and you don't mention free() ;-)
    You are probably going to need malloc() and realloc() and free()
    afterwards to get rid of the memory once you don't need it any-
    more (calloc() probably won't be too useful here). What would be
    the best solution depends a lot on your requirements, so it's a
    bit like asking "Which is the best car?". What exactly do you
    have problems with and how far did you got? It's usually a lot
    easier to discuss things when one has some code to start with.
    Or are you complete lost? And do you understand how pointers
    work? If not you probably should start learning about them (plus
    the methods for memory allocation) using some simpler examples
    than the task you're talking about.

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, May 13, 2005
    #3
  4. jesper

    -berlin.de Guest

    Achintya <> wrote:
    > Hoping that you can use STLs in your set-up...one solution can be....
    > list<vector<string> >


    Not very likely when the OP is asking in comp.lang.c, isn't it?

    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, May 13, 2005
    #4
  5. jesper

    Targeur fou Guest

    jesper a écrit :
    > Hello,


    Hello,

    > I have to load strings from a datbase and put them into an array.
    > I get them by packets of 100 strings of 50 characters.
    > Then I should do something like that : StringArray[x*100][50]


    Assuming that you have only a packet (x=1), I don't think that it would
    be the correct (easiest) form to deal with 100 strings of 50
    characters.
    char StringArray[50][100] would be better. In that way, your strings
    are "organized by lines" (X myArray[COLUMN][ROW];), and when you want
    to access to the i-th string, you just have to write StringArray.

    A basic and first possible approach is to define a packet type and then
    use pointers to packet typed variables.

    exple:
    typedef char StringsPacket[50][100];
    StringsPacket * packets;

    But this is ugly and difficult to handle. Furthermore It hides the
    array type of StringsPacket.

    A better way to do it is to use structures to split your data in simple
    items.

    exple:
    /**
    * @def LG_MAX
    * Max length of a string, including the '\0'
    */
    #define LG_MAX 50

    /**
    * @def NB_STR_PACKET
    * Number of strings per packet
    */
    #define NB_STR_PACKET 100

    /**
    * @struct typeString_s
    * Structure type used for a string
    */
    typedef struct typeString_s {
    char str[LG_MAX]; /* String */
    unsigned pos; /* Position in the packet (subscript)*/
    }String_s;

    /**
    * @struct typeStringPacket_s
    * Structure type that describes a packet of strings
    */
    typedef struct typeStringPacket_s {
    String_s str_arr[NB_STR_PACKET]; /* Array of String_s */
    }StringPacket_s;

    /**
    * @struct typeNodePacket_s
    */
    typedef struct typeNodePacket_s {
    StringPacket_s packet; /* Packet */
    struct typePacket_s * next; /* Next packet in the list */
    }NodePacket_s;

    In that way, it is easy to handle a linked list of NodePacket_s. This
    is a common used solution when you don't know the number of data items
    to handle. Here, you'll just have to allocate (and free) NodePackets_s*
    variables as needed with malloc(or calloc)/free. realloc() isn't really
    useful here.

    HTH
    Regis
    Targeur fou, May 13, 2005
    #5
  6. jesper

    CBFalconer Guest

    Achintya wrote:
    >
    > Hoping that you can use STLs in your set-up...one solution can be....
    >
    > list<vector<string> >


    C++ is off-topic in c.l.c. We deal with the C language.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
    CBFalconer, May 13, 2005
    #6
  7. jesper

    Al Bowers Guest

    jesper wrote:
    > Hello,
    >
    > I have to load strings from a datbase and put them into an array.
    > I get them by packets of 100 strings of 50 characters.
    > Then I should do something like that : StringArray[x*100][50]
    > But x can be huge, then I must allocate it dynamically.
    >


    As I understand, your input,ie. packets, is firm at 100 strings of
    50 characters. But the number of packets is unknown.

    Then one possiblity may be to declare a StringArray
    typedef char StringArray[100][50];

    And make a data struct like

    struct PACKET
    {
    StringArray *packet;
    unsigned packet_nr;
    }

    Define a function that will allocate an array of packet
    growing with you needs. See function AddPACKET below.

    You will need a function that copies the packet into
    the allocated space. In a example below I use the function
    GetPacket. And as a test this function reads a text file stream
    and stores the data in the newly allocated packet element.
    Of course, you would have to adapt that function to your steam
    requirements.

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

    #define NR_STR 100
    #define SZ_STR 50

    typedef char StringArray[NR_STR][SZ_STR];
    typedef enum PERR {NO_ERROR, ALLOC_FAILURE, STREAM_ERROR}PERR;

    PERR packeterror;

    typedef struct PACKET
    {
    StringArray *packet;
    unsigned nr_packets;
    } PACKET;
    /* Prototypes */
    int GetPacket(StringArray p, FILE *stream);
    StringArray *AddPACKET(PACKET *p, FILE *stream);
    void PrintStringArray(StringArray p, FILE *ostream);
    void FreePACKET(PACKET *p);

    int main(void)
    {
    FILE *fp;
    PACKET mypackets= {NULL};
    StringArray *pac;

    if((fp = fopen("test.c","r")) != NULL)
    {
    if((pac=AddPACKET(&mypackets,fp)) != NULL)
    PrintStringArray(*pac,stdout);
    else switch(packeterror)
    {
    case ALLOC_FAILURE: puts("Allocation failure");
    break;
    case STREAM_ERROR: puts("Stream error");
    break;
    case NO_ERROR: puts("Unspecified ERROR");
    };
    fclose(fp);
    FreePACKET(&mypackets);
    }
    else puts("Unable to open stream");
    return 0;
    }

    void FreePACKET(PACKET *p)
    {
    free(p->packet);
    p->packet = NULL;
    p->nr_packets = 0U;
    return;
    }

    StringArray *AddPACKET(PACKET *p, FILE *stream)
    {
    StringArray *tmp;

    packeterror = NO_ERROR;
    tmp = realloc(p->packet,(p->nr_packets+1)*sizeof *tmp);
    if(tmp == NULL)
    {
    packeterror = ALLOC_FAILURE;
    return NULL;
    }
    p->packet = tmp;
    if(!GetPacket(p->packet[p->nr_packets], stream))
    return NULL;
    return &p->packet[p->nr_packets++];
    }

    void PrintStringArray(StringArray p, FILE *ostream)
    {
    unsigned i;

    for(i = 0; i < NR_STR; i++)
    printf("%s",p);
    putchar('\n');
    return;
    }

    int GetPacket(StringArray p, FILE *stream)
    {
    unsigned i;

    packeterror = NO_ERROR;
    for(i = 0;i < NR_STR; i++)
    if(!fgets(p,SZ_STR,stream))
    {
    packeterror = STREAM_ERROR;
    return 0;
    }
    return 1;
    }

    --
    Al Bowers
    Tampa, Fl USA
    mailto: (remove the x to send email)
    http://www.geocities.com/abowers822/
    Al Bowers, May 13, 2005
    #7
  8. jesper

    Targeur fou Guest

    Targeur fou a écrit :
    > jesper a écrit :
    > > Hello,

    >
    > Hello,
    >
    > > I have to load strings from a datbase and put them into an array.
    > > I get them by packets of 100 strings of 50 characters.
    > > Then I should do something like that : StringArray[x*100][50]

    >
    > Assuming that you have only a packet (x=1), I don't think that it

    would
    > be the correct (easiest) form to deal with 100 strings of 50
    > characters.
    > char StringArray[50][100] would be better. In that way, your strings
    > are "organized by lines" (X myArray[COLUMN][ROW];), and when you want
    > to access to the i-th string, you just have to write StringArray.


    Sorry, I said bullshits just above. It's char StringArray[100][50], you
    were right. 2D arrays aren't so easy to use...

    My apologies.

    Regis
    Targeur fou, May 13, 2005
    #8
  9. jesper

    jesper Guest

    "jesper" <> wrote in message
    news:428488f1$0$23872$...
    > I have to load strings from a datbase and put them into an array.
    > I get them by packets of 100 strings of 50 characters.


    Thanks for answers.
    In fact my loading works, but it's the "free()" which crashes.
    I absolutely need to free allocated memory, as I have many other arrays to
    fill afterwards.
    I did this, just for test (contiguous array) :

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

    #define NBENR 100

    int main(int argc, char* argv[])
    {
    char sBuffer[50];
    int i;
    int j, k;

    j=0;
    while (j<=1000)
    {
    char **sArray = (char **)malloc(NBENR * sizeof(char *));
    sArray[0] = (char*)malloc(NBENR * 50 * sizeof(char));
    for(k= i = j; i <= k+ NBENR; i++)
    {
    sArray = sArray[0] + i * 50;
    sprintf(sBuffer, "String[%d]\n", j);
    strcpy(sArray, sBuffer);
    printf(sArray);
    j++;
    if (j> 1000)
    break;
    }
    // crashes !!!
    free((char*)sArray[0]);

    }
    return 0;
    }
    jesper, May 14, 2005
    #9
  10. jesper

    Targeur fou Guest

    jesper a écrit :

    Hi,

    > "jesper" <> wrote in message
    > news:428488f1$0$23872$...
    > > I have to load strings from a datbase and put them into an array.
    > > I get them by packets of 100 strings of 50 characters.

    >
    > Thanks for answers.
    > In fact my loading works, but it's the "free()" which crashes.
    > I absolutely need to free allocated memory, as I have many other

    arrays to
    > fill afterwards.
    > I did this, just for test (contiguous array) :
    >
    > #include <stdlib.h>
    > #include <string.h>
    >
    > #define NBENR 100
    >
    > int main(int argc, char* argv[])
    > {
    > char sBuffer[50];
    > int i;
    > int j, k;
    >
    > j=0;
    > while (j<=1000)
    > {
    > char **sArray = (char **)malloc(NBENR * sizeof(char *));


    Notice that you have to test the return of malloc here.

    > sArray[0] = (char*)malloc(NBENR * 50 * sizeof(char));


    The same here. But I wonder why you don't allocate 50 characters for
    each pointer to pointer to char in the packet.

    e.g:

    char **sArray = malloc(NBENR * sizeof (char**));
    if (sArray != NULL)
    {
    /* Loop to allocate memory for each string in the packet */
    int i, j, brkFlag = 0;
    for (i=0, j=0; i<NBENR; ++i, ++j)
    {
    sArray = malloc(50);
    /* Trace and break the loop in case of failure */
    if (sArray == NULL)
    {
    fprintf(stderr,
    "Failed to allocate memory for the %d string in the
    packet\n",
    i+1);
    brkFlag = 1;
    break;
    }
    }

    if ( brkFlag != 0)
    /* Loop to free already allocated items if it failed above */
    for(i=0; i<=j && brkFlag ==1; ++i)
    {
    free(sArray);
    }
    free(sArray);
    exit(EXIT_FAILURE);
    }

    /* PROCESSING HERE */

    /* Loop to free already memory items */
    for(i=0; i<=j; ++i)
    {
    free(sArray);
    }
    /* At last, free the pointer to pointers to char */
    free(sArray);

    }
    else
    {
    fprintf(stderr,
    "Failed to allocate memory for the pointer to pointers to
    char\n");
    }

    > for(k= i = j; i <= k+ NBENR; i++)
    > {
    > sArray = sArray[0] + i * 50;
    > sprintf(sBuffer, "String[%d]\n", j);
    > strcpy(sArray, sBuffer);
    > printf(sArray);
    > j++;
    > if (j> 1000)
    > break;
    > }
    > // crashes !!!
    > free((char*)sArray[0]);


    Surprising. Are you sure sArray[0] (its value) isn't modified somewhere
    in your program (realloc(), a shift...) ? You retrieved a pointer value
    with malloc() but it shall be the same pointer value to pass to free()
    to avoid crashes.

    HTH
    Regis
    Targeur fou, May 14, 2005
    #10
  11. jesper

    Axter Guest

    jesper wrote:
    > Hello,
    >
    > I have to load strings from a datbase and put them into an array.
    > I get them by packets of 100 strings of 50 characters.
    > Then I should do something like that : StringArray[x*100][50]
    > But x can be huge, then I must allocate it dynamically.
    >
    > I have searched on Google, but I only found different solutions

    (malloc,
    > realloc, calloc, ...)
    > What could be the best solution ?
    >
    > Thanks in advance.


    You can use a wrapper function like that in the following link:
    http://code.axter.com/allocate2darray.h
    http://code.axter.com/allocate2darray.c
    Example usage:
    char **StringArray = ALLOCATE2DARRAY(char, x*100, 50);

    You can access above type with [][]
    Axter, May 15, 2005
    #11
  12. jesper

    Flash Gordon Guest

    Axter wrote:
    > jesper wrote:
    >
    >>Hello,
    >>
    >>I have to load strings from a datbase and put them into an array.
    >>I get them by packets of 100 strings of 50 characters.
    >>Then I should do something like that : StringArray[x*100][50]
    >>But x can be huge, then I must allocate it dynamically.
    >>
    >>I have searched on Google, but I only found different solutions
    >>(malloc, realloc, calloc, ...)
    >>What could be the best solution ?
    >>
    >>Thanks in advance.

    >
    > You can use a wrapper function like that in the following link:
    > http://code.axter.com/allocate2darray.h
    > http://code.axter.com/allocate2darray.c
    > Example usage:
    > char **StringArray = ALLOCATE2DARRAY(char, x*100, 50);
    >
    > You can access above type with [][]


    You suggested this code to someone else back on the 30th April, and is
    was explained back then why this code is not portable.

    Your code assumes that the void** can be converted to a valid Type**
    pointer which is not guaranteed by the standard. It also assumes that
    the representation of void* is the same as Type* (I think the standard
    says something about this for Type==char, but not in general).

    You even admitted on May 1st Message-ID:
    <> that it was
    possible for sizeof(void*) to be different from sizeof(Type*) and that
    your code was therefore not portable.

    Recommending non-portable code without clearly stating it is
    non-portable is not a nice thing to do. Especially on a group dedicated
    to portable programming.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.
    Flash Gordon, May 15, 2005
    #12
  13. jesper

    Axter Guest

    Flash Gordon wrote:
    > Axter wrote:
    > > jesper wrote:
    > >
    > >>Hello,
    > >>
    > >>I have to load strings from a datbase and put them into an array.
    > >>I get them by packets of 100 strings of 50 characters.
    > >>Then I should do something like that : StringArray[x*100][50]
    > >>But x can be huge, then I must allocate it dynamically.
    > >>
    > >>I have searched on Google, but I only found different solutions
    > >>(malloc, realloc, calloc, ...)
    > >>What could be the best solution ?
    > >>
    > >>Thanks in advance.

    > >
    > > You can use a wrapper function like that in the following link:
    > > http://code.axter.com/allocate2darray.h
    > > http://code.axter.com/allocate2darray.c
    > > Example usage:
    > > char **StringArray = ALLOCATE2DARRAY(char, x*100, 50);
    > >
    > > You can access above type with [][]

    >
    > You suggested this code to someone else back on the 30th April, and

    is
    > was explained back then why this code is not portable.
    >
    > Your code assumes that the void** can be converted to a valid Type**
    > pointer which is not guaranteed by the standard. It also assumes that


    > the representation of void* is the same as Type* (I think the

    standard
    > says something about this for Type==char, but not in general).
    >
    > You even admitted on May 1st Message-ID:
    > <> that it was
    > possible for sizeof(void*) to be different from sizeof(Type*) and

    that
    > your code was therefore not portable.
    >
    > Recommending non-portable code without clearly stating it is
    > non-portable is not a nice thing to do. Especially on a group

    dedicated
    > to portable programming.
    > --
    > Flash Gordon
    > Living in interesting times.
    > Although my email address says spam, it is real and I read it.
    >>> The code is portable if used with a char type.

    > Read the C standard section section 6.2.5-26.
    >>I stated that I thought that the standard stated something about

    char,
    >>however you did not state that your code only works for char despite
    >>what the comments say.


    If you had bother to read the *.c file, and read the comments at the
    bottom, you see that I made a full disclosure on the code's portability
    issue, with direct reference to the standard.

    The code is portable when used with a char type, and that's is what the
    questioner is asking about.
    Your complaint of non-portability is out of topic for this paticular
    question.

    >>If you had stated it was only suitable for char that would have been
    >>been fine. Although you should also change the comments and/or change

    it
    >>to using char type.

    I don't have to state that, if the questioner not asking about other
    types or types in general.
    The question was specific.
    If you want to give that additional information, please feel free to do
    so, but please don't try and tell me how I should give advise.

    >>In your code you state it works for any type, therefore it is not
    >>portable. If it stated it was only portable for char I would not have


    >>commented.


    It does state that in the implementation. Please do your homework.

    IMHO, is more inappropriate for you to state that the code is not
    portable, with stating that it is portable for the example I posted,
    and for the specific question asked.

    > Recommending non-portable code without clearly stating it is
    > non-portable is not a nice thing to do. Especially on a group

    dedicated
    > to portable programming.
    > --
    > Flash Gordon
    > Living in interesting times.


    Stating something is not portable, when the specific code posted is
    portable, is not a nice thing to do, and moreover, it's basically a
    lie.

    If you would have stated that it's not portable with any other type
    other then char, then that would be truthful.
    But what you stated is misleading at best, and a lie at worse. This
    does do well for your credibility.

    When critiquing someone in the future, please try to be a little more
    honest, or at least a little more accurate.

    FYI:
    Sorry for emailing my last reply. I click the wrong Google button.
    Axter, May 15, 2005
    #13
  14. If your database is a file, get FreeDOS Edlin 2.5 (available on ibiblio
    or the alt.sources newsgroup) and borrow that code.

    Gregory Pietsch
    Gregory Pietsch, May 25, 2005
    #14
    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. Venkat
    Replies:
    4
    Views:
    961
    Venkat
    Dec 5, 2003
  2. Kurt Krueckeberg
    Replies:
    2
    Views:
    694
    =?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunino?=
    Nov 17, 2004
  3. Rick

    Comparing strings from within strings

    Rick, Oct 21, 2003, in forum: C Programming
    Replies:
    3
    Views:
    367
    Irrwahn Grausewitz
    Oct 21, 2003
  4. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    733
    Malcolm
    Jun 24, 2006
  5. Amit  Limaye
    Replies:
    4
    Views:
    443
    Phlip
    Apr 10, 2006
Loading...

Share This Page