Array of strings

J

jesper

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.
 
A

Achintya

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...
 
J

Jens.Toerring

jesper said:
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
 
J

Jens.Toerring

Achintya said:
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
 
T

Targeur fou

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
 
C

CBFalconer

Achintya said:
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.
 
A

Al Bowers

jesper said:
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;
}
 
T

Targeur fou

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
 
J

jesper

jesper said:
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;
}
 
T

Targeur fou

jesper a écrit :

Hi,
jesper said:
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
 
A

Axter

jesper said:
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 [][]
 
F

Flash Gordon

Axter said:
jesper said:
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:
<[email protected]> 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.
 
A

Axter

Flash said:
Axter said:
jesper said:
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:
<[email protected]> 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.
Read the C standard section section 6.2.5-26.

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.
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.

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.

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.
 
G

Gregory Pietsch

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top