473,394 Members | 1,640 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

an interesting problem in c

Hi Everyone,

I have the following structure in my program

struct sample
{
char *string;
int string_len;
};

struct sample **ptr; //serves as two-dimentional array

Now, based on run-time input, i will be allocating the memory for ptr
such that i have a 1d array of pointers to structure sample, and each
member will be holding a string, now the problem i have is that the
following is the run time input, say in a file,

string1
string2
string3

now, i need to allocate ptr to hold three set of struct sample and
store each of the string in one member's string (after allocation),
something like

struct sample ptr = (struct sample**)malloc(<value>*sizeof(struct
sample*));
for(i=0;i<value;i++)
{
struct sample ptr[i] = (struct sample*)malloc(sizeof(struct sample));
sample[i].string = (char*)malloc(100); //each will hold the string
}
The problem i'm facing is that i don't know the value in advance
(which i will know only after the end of the file), please give me any
suggestions as to how to do it?

Dec 19 '06 #1
22 1871
sa*****@yahoo.co.in wrote:
I have the following structure in my program

struct sample {
char *string;
int string_len;
};

struct sample **ptr; //serves as two-dimentional array

Now, based on run-time input, i will be allocating the memory for ptr
such that i have a 1d array of pointers to structure sample, and each
member will be holding a string, now the problem i have is that the
following is the run time input, say in a file,

string1
string2
string3

now, i need to allocate ptr to hold three set of struct sample and
store each of the string in one member's string (after allocation),
something like

struct sample ptr = (struct sample**)malloc(<value>*sizeof(struct sample*));
for(i=0;i<value;i++) {
struct sample ptr[i] = (struct sample*)malloc(sizeof(struct sample));
sample[i].string = (char*)malloc(100); //each will hold the string
}

The problem i'm facing is that i don't know the value in advance
(which i will know only after the end of the file), please give me any
suggestions as to how to do it?
I've written an entire library that solves this exact problem (and
others.) You can read about it here:

http://bstring.sf.net/

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Dec 19 '06 #2

sa*****@yahoo.co.in wrote:
Hi Everyone,

I have the following structure in my program

struct sample
{
char *string;
int string_len;
};

struct sample **ptr; //serves as two-dimentional array

Now, based on run-time input, i will be allocating the memory for ptr
such that i have a 1d array of pointers to structure sample, and each
member will be holding a string, ...
[snip]
The problem i'm facing is that i don't know the value in advance
(which i will know only after the end of the file), please give me any
suggestions as to how to do it?
You could look at something involving realloc() - allocating an initial
reasonable value for the array of pointers and increasing by a suitable
factor when it overflows.

You could look at a two-pass approach - either read the file once to
determine how much data you have, size the array and then read again;
or read the data initially into a different structure - say a linked
list - and transform it to an array once you have all the data.

Dec 19 '06 #3
>
You could look at something involving realloc() - allocating an initial
reasonable value for the array of pointers and increasing by a suitable
factor when it overflows.

You could look at a two-pass approach - either read the file once to
determine how much data you have, size the array and then read again;
or read the data initially into a different structure - say a linked
list - and transform it to an array once you have all the data.
I can't afford parsing the file two times and neither can i have a
temp list to hold all the values, first one is costly from time
prespective and second one is costly from memory prespective... so i
guess i'm left out with only realloc(), i have never used one... does
it make sure that old block's values are retained when i decide to
re-alloc?

Dec 19 '06 #4
sa*****@yahoo.co.in said:

<snip>
I can't afford parsing the file two times and neither can i have a
temp list to hold all the values, first one is costly from time
prespective and second one is costly from memory prespective... so i
guess i'm left out with only realloc(), i have never used one... does
it make sure that old block's values are retained when i decide to
re-alloc?
Yes, even if the reallocation fails and realloc returns NULL (which it
might).

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 19 '06 #5
>
Yes, even if the reallocation fails and realloc returns NULL (which it
might).
Do you mean, even if re-alloc fails due to memory shortage, it would
return NULL and it wouldn't disturb the old memory which was previously
allocated?

Dec 19 '06 #6
sa*****@yahoo.co.in said:
>
>>
Yes, even if the reallocation fails and realloc returns NULL (which it
might).

Do you mean, even if re-alloc fails due to memory shortage, it would
return NULL and it wouldn't disturb the old memory which was previously
allocated?
Correct. BUT that does require a little effort on your part, if you don't
want to lose track of that old memory.

#include <stdlib.h>

int main(void)
{
int *tmp = NULL;
size_t n = 1024;

int *p = malloc(n * sizeof *p);
if(p != NULL)
{
int i;
for(i = 0; i < n; i++)
{
p[i] = i;
}
/* now let's try to get some more memory */
n *= 2;
tmp = realloc(p, n * sizeof *p);
if(tmp == NULL)
{
/* the allocation FAILED, but because we used tmp to detect
this, we can still get to the old block, using p, which
still points to the old block.
*/
}
else
{
/* the allocation SUCCEEDED. p is now invalid, but we can
safely fix that now:
*/
p = tmp;
while(i < n)
{
p[i] = i;

etc etc etc
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 19 '06 #7

sa*****@yahoo.co.in wrote:
Hi Everyone,

I have the following structure in my program

struct sample
{
char *string;
int string_len;
};

struct sample **ptr; //serves as two-dimentional array

Now, based on run-time input, i will be allocating the memory for ptr
such that i have a 1d array of pointers to structure sample, and each
member will be holding a string, now the problem i have is that the
following is the run time input, say in a file,

string1
string2
string3

now, i need to allocate ptr to hold three set of struct sample and
store each of the string in one member's string (after allocation),
something like

struct sample ptr = (struct sample**)malloc(<value>*sizeof(struct
sample*));
for(i=0;i<value;i++)
{
struct sample ptr[i] = (struct sample*)malloc(sizeof(struct sample));
sample[i].string = (char*)malloc(100); //each will hold the string
}
The problem i'm facing is that i don't know the value in advance
(which i will know only after the end of the file), please give me any
suggestions as to how to do it?
member will be holding a string, now the problem i have is that the
following is the run time input, say in a file,

string1
string2
string3

now, i need to allocate ptr to hold three set of struct sample and
store each of the string in one member's string (after allocation),
something like

struct sample ptr = (struct sample**)malloc(<value>*sizeof(struct
sample*));
for(i=0;i<value;i++)
{
struct sample ptr[i] = (struct sample*)malloc(sizeof(struct sample));
sample[i].string = (char*)malloc(100); //each will hold the string
}

The problem i'm facing is that i don't know the value in advance
(which i will know only after the end of the file), please give me any
suggestions as to how to do it?
The best strategy will depend on the characteristics of typical input.

If possible, one option is to read the input twice, once to count the
number of string pointers needed and a second time to input them and
set the pointers into your dynamic array.

If the input can be read more than once, another option is to count the
number of strings and also accumulate the total number of characters in
them on the first run. Before the second run the pointer array is
allocated for the number of strings plus one and a single array of
characters is allocated for the total number of characters (you might
also want the nul terminators as well).

Then as the strings are read in they are placed 'end to end' in the
large character array and their start positions are recorded in the
pointer array. At the end the last pointer is set to one past the top
of the character array. Now the strings are contained between
consecutive pointer values. This avoids the overhead of many individual
memory allocations for each of the strings and simplifies the memory
allocation and deallocation tasks.

But if the input can only be read once you may need to allocate for a
fixed number of pointers and then to input strings until either the end
of the input or this number is reached. If the pointer array becomes
full before the end of file you can then use realloc() to obtain a
larger block of memory for your structure whilst preserving the
previous values you have set (the block might move but the values are
preserved).

How much to memory to allocate initially for pointers and how expand
the block each time you fill it will again depend on the typical
characteristics of your inputs.

Cactus

Dec 19 '06 #8

sa*****@yahoo.co.in wrote:

You could look at something involving realloc() - allocating an initial
reasonable value for the array of pointers and increasing by a suitable
factor when it overflows.

You could look at a two-pass approach - either read the file once to
determine how much data you have, size the array and then read again;
or read the data initially into a different structure - say a linked
list - and transform it to an array once you have all the data.

I can't afford parsing the file two times and neither can i have a
temp list to hold all the values, first one is costly from time
prespective and second one is costly from memory prespective...
The same set of structures can be members both of the linked list and
the array, of course...

Dec 19 '06 #9
>
#include <stdlib.h>

int main(void)
{
int *tmp = NULL;
size_t n = 1024;

int *p = malloc(n * sizeof *p);
if(p != NULL)
{
int i;
for(i = 0; i < n; i++)
{
p[i] = i;
}
/* now let's try to get some more memory */
n *= 2;
tmp = realloc(p, n * sizeof *p);
if(tmp == NULL)
{
/* the allocation FAILED, but because we used tmp to detect
this, we can still get to the old block, using p, which
still points to the old block.
*/
}
else
{
/* the allocation SUCCEEDED. p is now invalid, but we can
safely fix that now:
*/
p = tmp;
while(i < n)
{
p[i] = i;

etc etc etc
--
I see what you are trying to say, to consider the return value of
re-alloc() when it is successful and when it fails, stick to the old
pointer. And i' m trying to understand as to how re-alloc() works, does
it try to allocate memory at the end of the current chunk and if it
can't do because memory next to current chunk is not free, it would
allocate a whole new block to hold old value and copies old value to
new block making sure new memory is good enough to satisfy the memory
request and free the old block...

Is my understanding correct?

Dec 19 '06 #10
sa*****@yahoo.co.in said:

<snip>
I see what you are trying to say, to consider the return value of
re-alloc()
realloc()
when it is successful and when it fails, stick to the old
pointer.
Right.
And i' m trying to understand as to how re-alloc() works, does
it try to allocate memory at the end of the current chunk and if it
can't do because memory next to current chunk is not free, it would
allocate a whole new block to hold old value and copies old value to
new block making sure new memory is good enough to satisfy the memory
request and free the old block...
....if it can find such a block, yes. Otherwise, the existing memory block
will be left alone and realloc() will return NULL.
>
Is my understanding correct?
Yes, that's a perfectly reasonable description of realloc()'s behaviour.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 19 '06 #11
Richard Heathfield wrote:
sa*****@yahoo.co.in said:
.... snip ...
>
>And i' m trying to understand as to how re-alloc() works, does
it try to allocate memory at the end of the current chunk and
if it can't do because memory next to current chunk is not free,
it would allocate a whole new block to hold old value and copies
old value to new block making sure new memory is good enough to
satisfy the memory request and free the old block...

...if it can find such a block, yes. Otherwise, the existing
memory block will be left alone and realloc() will return NULL.
> Is my understanding correct?

Yes, that's a perfectly reasonable description of realloc()'s
behaviour.
Reasonable, yes. Required, no.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Dec 19 '06 #12
CBFalconer said:
Richard Heathfield wrote:
>sa*****@yahoo.co.in said:
... snip ...
>>
>>And i' m trying to understand as to how re-alloc() works, does
it try to allocate memory at the end of the current chunk and
if it can't do because memory next to current chunk is not free,
it would allocate a whole new block to hold old value and copies
old value to new block making sure new memory is good enough to
satisfy the memory request and free the old block...

...if it can find such a block, yes. Otherwise, the existing
memory block will be left alone and realloc() will return NULL.
>> Is my understanding correct?

Yes, that's a perfectly reasonable description of realloc()'s
behaviour.

Reasonable, yes. Required, no.
Would you care to expand on that, Chuck?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 19 '06 #13
Richard Heathfield wrote:
CBFalconer said:
>Richard Heathfield wrote:
>>sa*****@yahoo.co.in said:
... snip ...
>>>
And i' m trying to understand as to how re-alloc() works, does
it try to allocate memory at the end of the current chunk and
if it can't do because memory next to current chunk is not free,
it would allocate a whole new block to hold old value and copies
old value to new block making sure new memory is good enough to
satisfy the memory request and free the old block...

...if it can find such a block, yes. Otherwise, the existing
memory block will be left alone and realloc() will return NULL.

Is my understanding correct?

Yes, that's a perfectly reasonable description of realloc()'s
behaviour.

Reasonable, yes. Required, no.

Would you care to expand on that, Chuck?
There is no requirement to attempt to preserve the same pointer and
avoid data copying. My nmalloc goes to lengths to avoid the
copying overhead, but it is not required in order to have a working
malloc system.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Dec 19 '06 #14
sa*****@yahoo.co.in wrote:
I can't afford parsing the file two times
Not even if you use the rewind function?

Depending on what you're parsing for,
sometimes you can go through a file twice pretty quick.

unsigned long max_line_len(FILE *fd)
{
unsigned long count, max;
int rc;

count = max = 0;
while ((rc = getc(fd)) != EOF) {
if (rc == '\n') {
if (count max) {
max = count;
}
count = 0;
} else {
++count;
}
}
rewind(fd);
return max;
}

--
pete
Dec 19 '06 #15
CBFalconer said:
Richard Heathfield wrote:
>CBFalconer said:
>>Richard Heathfield wrote:
<snip>
>>>>
Yes, that's a perfectly reasonable description of realloc()'s
behaviour.

Reasonable, yes. Required, no.

Would you care to expand on that, Chuck?

There is no requirement to attempt to preserve the same pointer and
avoid data copying.
Oh, that's what you meant. And yes, of course you are right. Sorry for not
making that clear in my own reply.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 19 '06 #16
pete <pf*****@mindspring.comwrites:
sa*****@yahoo.co.in wrote:
> I can't afford parsing the file two times

Not even if you use the rewind function?

Depending on what you're parsing for,
sometimes you can go through a file twice pretty quick.
rewind() doesn't always work; try rewinding a keyboard.

And the rewind() function in particular has no way to report an error.
If you want to *try* to rewind a stream, use fseek() instead.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Dec 20 '06 #17
sa*****@yahoo.co.in wrote:
>
>You could look at something involving realloc() - allocating an
initial reasonable value for the array of pointers and increasing
by a suitable factor when it overflows.

You could look at a two-pass approach - either read the file once
to determine how much data you have, size the array and then read
again; or read the data initially into a different structure -
say a linked list - and transform it to an array once you have all
the data.

I can't afford parsing the file two times and neither can i have a
temp list to hold all the values, first one is costly from time
prespective and second one is costly from memory prespective... so
i guess i'm left out with only realloc(), i have never used one...
does it make sure that old block's values are retained when i
decide to re-alloc?
Please don't strip attributions for material you quote. Those are
the initial lines that read "joe wrote:".

Take a look at the methods used in freverse.c, which is a
demonstration and test program that comes with the ggets package.
In turn, ggets can be found at:

<http://cbfalconer.home.att.net/download/>

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Dec 20 '06 #18
Keith Thompson wrote:
>
pete <pf*****@mindspring.comwrites:
sa*****@yahoo.co.in wrote:
I can't afford parsing the file two times
Not even if you use the rewind function?

Depending on what you're parsing for,
sometimes you can go through a file twice pretty quick.

rewind() doesn't always work;
OK, well ...,
if OP wants to make an array of struct sample,
then one of the interesting properties of
a linked list of generic nodes,
is that the list nodes can be freed
while the node's data pointers remain valid.

/* BEGIN array_from_list.c */
/*
** get_line reads a line from a text stream
** and writes the characters to an array of char,
** replacing the newline character with a null character.
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
/*
** INITIAL_BUFFER_SIZE can be any number.
** If INITIAL_BUFFER_SIZE is equal to the number of
** characters in the longest input line,
** then no further allocation will be needed.
*/
#define INITIAL_BUFFER_SIZE 0

struct sample {
char *string;
size_t string_len;
};

struct list_node {
struct list_node *next;
void *data;
};

int get_line(char **lineptr, size_t *n, FILE *stream);
struct list_node *sample_node(struct list_node **head,
struct list_node *tail,
char *data);
void list_free(struct list_node *node, void (*free_data)(void *));
int sample_fprintf(struct list_node *node, FILE *stream);
void sample_free(void *data);
void no_data_free(void *data);

int main(void)
{
struct list_node *head, *tail, *list_ptr;
int rc;
char *buff_ptr;
size_t buff_size;
long unsigned line_count, index;
struct sample **array;

buff_size = INITIAL_BUFFER_SIZE;
buff_ptr = malloc(buff_size);
if (buff_ptr == NULL && buff_size != 0) {
printf("malloc(%lu) == NULL\n", (long unsigned)buff_size);
buff_size = 0;
}
tail = head = NULL;
line_count = 0;
puts("\nThis program makes and prints a list of all the lines\n"
"of text entered from standard input.\n"
"Just hit the Enter key to end,\n"
"or enter any line of characters to continue.");
while ((rc = get_line(&buff_ptr, &buff_size, stdin)) 1) {
++line_count;
tail = sample_node(&head, tail, buff_ptr);
if (tail == NULL) {
break;
}
puts("\nJust hit the Enter key to end,\n"
"or enter any line of characters to continue.");
}
switch (rc) {
case EOF:
if (buff_ptr != NULL && strlen(buff_ptr) != 0) {
puts("rc equals EOF\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = sample_node(&head, tail, buff_ptr);
}
break;
case 0:
puts("realloc returned a null pointer value");
if (buff_size 1) {
puts("rc equals 0\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = sample_node(&head, tail, buff_ptr);
}
break;
default:
break;
}
if (line_count != 0 && tail == NULL) {
puts("Node allocation failed.");
puts("The last line entered didn't make it onto the list:");
puts(buff_ptr);
}
free(buff_ptr);
puts("\nThe line buffer has been freed.\n");
printf("%lu lines of text were entered.\n", line_count);
puts("They are:\n");
sample_fprintf(head, stdout);
array = malloc(line_count * sizeof *array);
if (array != NULL) {
list_ptr = head;
for (index = 0; index != line_count; ++index) {
array[index] = list_ptr -data;
list_ptr = list_ptr -next;
}
list_free(head, no_data_free);
puts("\nThe list nodes have been freed,\n"
"but their data pointers are still valid.");
puts("\nThe array contents is:\n");
for (index = 0; index != line_count; ++index) {
printf("array[%lu] -string_len is %u\n"
"array[%lu] -string is:%s\n\n",
index,
(unsigned)(array[index] -string_len),
index,
array[index] -string);
}
for (index = 0; index != line_count; ++index) {
free(array[index]);
}
free(array);
puts("The array has been freed.");
} else {
list_free(head, sample_free);
puts("\narray == NULL. The list has been freed.\n");
}
return 0;
}

int get_line(char **lineptr, size_t *n, FILE *stream)
{
int rc;
void *p;
size_t count;

count = 0;
while ((rc = getc(stream)) != EOF) {
++count;
if (count + 2 *n) {
p = realloc(*lineptr, count + 2);
if (p == NULL) {
if (*n count) {
(*lineptr)[count] = '\0';
(*lineptr)[count - 1] = (char)rc;
} else {
ungetc(rc, stream);
}
count = 0;
break;
}
*lineptr = p;
*n = count + 2;
}
if (rc == '\n') {
(*lineptr)[count - 1] = '\0';
break;
}
(*lineptr)[count - 1] = (char)rc;
}
if (rc != EOF) {
rc = count INT_MAX ? INT_MAX : count;
} else {
if (*n count) {
(*lineptr)[count] = '\0';
}
}
return rc;
}

struct list_node *sample_node(struct list_node **head,
struct list_node *tail,
char *string)
{
struct list_node *node;
struct sample *sample_data;
size_t length;

node = malloc(sizeof *node);
if (node != NULL) {
node -next = NULL;
node -data = malloc(sizeof *sample_data);
if (node -data != NULL) {
length = strlen(string);
sample_data = node -data;
sample_data -string_len = length;
sample_data -string = malloc(length + 1);
if (sample_data -string != NULL) {
if (*head == NULL) {
*head = node;
} else {
tail -next = node;
}
memcpy(sample_data -string, string, length + 1);
} else {
free(node -data);
free(node);
node = NULL;
}
} else {
free(node);
node = NULL;
}
}
return node;
}

void list_free(struct list_node *node, void (*free_data)(void *))
{
struct list_node *next_node;

while (node != NULL) {
next_node = node -next;
free_data(node -data);
free(node);
node = next_node;
}
}

void sample_free(void *data)
{
free(((struct sample *)data) -string);
free(data);
}

void no_data_free(void *data)
{
data;
}

int sample_fprintf(struct list_node *node, FILE *stream)
{
struct sample s;

while (node != NULL) {
s = *(struct sample *)(node -data);
if (fprintf(stream,
"String length is %3u:%s\n",
(unsigned)s.string_len, s.string) == EOF)
{
break;
}
node = node -next;
}
return node == NULL ? '\n' : EOF;
}

/* END array_from_list.c */

--
pete
Dec 20 '06 #19
pete wrote:
>
Keith Thompson wrote:

pete <pf*****@mindspring.comwrites:
sa*****@yahoo.co.in wrote:
>
> I can't afford parsing the file two times
>
Not even if you use the rewind function?
>
Depending on what you're parsing for,
sometimes you can go through a file twice pretty quick.
rewind() doesn't always work;

OK, well ...,
if OP wants to make an array of struct sample,
then one of the interesting properties of
a linked list of generic nodes,
is that the list nodes can be freed
while the node's data pointers remain valid.
.... which only enables you to make
an array of pointers to struct sample,
but that's pretty close.

--
pete
Dec 20 '06 #20
hi dear richard !

this is gelareh . infact i wanted to get help from you if you can ,
my major is computer
infact i 'm familiar with language "c" to some extent but can not how
to work programming
i mean my base is weak but i have the tendancy to work programming i
wanted to get help
if it's possible for you just to introduce some good reference books
in c programming
and direct me how i can learn programming online and making projects if
i became more
exprienced . i request you from which titles should i begin to make
progress and be professional . thanks very much .and please excuse me
for talking so much.

Dec 20 '06 #21
pete wrote:
for (index = 0; index != line_count; ++index) {
free(array[index]);
}
free(array);
I forgot to free the strings!

Should be:

for (index = 0; index != line_count; ++index) {
free(array[index] -string);
free(array[index]);
}
free(array);

--
pete
Dec 20 '06 #22
pete wrote:
>
pete wrote:

Keith Thompson wrote:
>
pete <pf*****@mindspring.comwrites:
sa*****@yahoo.co.in wrote:

I can't afford parsing the file two times

Not even if you use the rewind function?

Depending on what you're parsing for,
sometimes you can go through a file twice pretty quick.
>
rewind() doesn't always work;
OK, well ...,
if OP wants to make an array of struct sample,
then one of the interesting properties of
a linked list of generic nodes,
is that the list nodes can be freed
while the node's data pointers remain valid.

... which only enables you to make
an array of pointers to struct sample,
but that's pretty close.
But making an array of structures instead of an
array of pointers from a list, isn't really any more difficult.
In this version, the structures and the list nodes
have pointers to non null terminated arrays instead of strings.

/* BEGIN array_from_list.c */

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

#define INITIAL_BUFFER_SIZE 0
/*
** The pointer variables called "string"
** in the struct sample declaration,
** and also in the sample_node function definition,
** actually point to non null terminated arrays
** of "length" number of characters.
*/
struct sample {
char *string;
long unsigned length;
};

struct list_node {
struct list_node *next;
void *data;
};

int get_line(char **lineptr, size_t *n, FILE *stream);
struct list_node *sample_node(struct list_node **head,
struct list_node *tail,
char *string);
void list_free(struct list_node *node, void (*free_data)(void *));
void sample_fprintf(struct list_node *node, FILE *stream);
void sample_free(void *data);

int main(void)
{
struct list_node *head, *tail, *list_ptr;
int rc;
char *buff_ptr, *ptr;
size_t buff_size;
long unsigned line_count, index, length;
struct sample *array;

buff_size = INITIAL_BUFFER_SIZE;
buff_ptr = malloc(buff_size);
if (buff_ptr == NULL && buff_size != 0) {
printf("malloc(%lu) == NULL\n", (long unsigned)buff_size);
buff_size = 0;
}
tail = head = NULL;
line_count = 0;
puts("\nThis program makes and prints a list of all the lines\n"
"of text entered from standard input.\n"
"Just hit the Enter key to end,\n"
"or enter any line of characters to continue.");
while ((rc = get_line(&buff_ptr, &buff_size, stdin)) 1) {
++line_count;
tail = sample_node(&head, tail, buff_ptr);
if (tail == NULL) {
break;
}
puts("\nJust hit the Enter key to end,\n"
"or enter any line of characters to continue.");
}
switch (rc) {
case EOF:
if (buff_ptr != NULL && strlen(buff_ptr) != 0) {
puts("rc equals EOF\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = sample_node(&head, tail, buff_ptr);
}
break;
case 0:
puts("realloc returned a null pointer value");
if (buff_size 1) {
puts("rc equals 0\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = sample_node(&head, tail, buff_ptr);
}
break;
default:
break;
}
if (line_count != 0 && tail == NULL) {
puts("Node allocation failed.");
puts("The last line entered didn't make it onto the list:");
puts(buff_ptr);
}
free(buff_ptr);
puts("\nThe line buffer has been freed.\n");
printf("%lu lines of text were entered.\n", line_count);
puts("They are:\n");
sample_fprintf(head, stdout);
array = malloc(line_count * sizeof *array);
if (array != NULL) {
list_ptr = head;
for (index = 0; index != line_count; ++index) {
array[index] = *(struct sample *)(list_ptr -data);
list_ptr = list_ptr -next;
}
list_free(head, free);
puts("\nThe list nodes have been freed,\n"
"but their string pointers are still valid.");
puts("\nThe array contents is:\n");
for (index = 0; index != line_count; ++index) {
printf("array[%lu].length is %lu\n"
"array[%lu].string is:",
index, array[index].length, index);
length = array[index].length;
ptr = array[index].string;
while (length-- != 0) {
putchar(*ptr++);
}
puts("\n");
}
for (index = 0; index != line_count; ++index) {
free(array[index].string);
}
free(array);
puts("The array has been freed.");
} else {
list_free(head, sample_free);
puts("\narray == NULL. The list has been freed.\n");
}
return 0;
}

int get_line(char **lineptr, size_t *n, FILE *stream)
{
int rc;
void *p;
size_t count;

count = 0;
while ((rc = getc(stream)) != EOF) {
++count;
if (count + 2 *n) {
p = realloc(*lineptr, count + 2);
if (p == NULL) {
if (*n count) {
(*lineptr)[count] = '\0';
(*lineptr)[count - 1] = (char)rc;
} else {
ungetc(rc, stream);
}
count = 0;
break;
}
*lineptr = p;
*n = count + 2;
}
if (rc == '\n') {
(*lineptr)[count - 1] = '\0';
break;
}
(*lineptr)[count - 1] = (char)rc;
}
if (rc != EOF) {
rc = count INT_MAX ? INT_MAX : count;
} else {
if (*n count) {
(*lineptr)[count] = '\0';
}
}
return rc;
}

struct list_node *sample_node(struct list_node **head,
struct list_node *tail,
char *string)
{
struct list_node *node;
struct sample *sample_data;
size_t length;

node = malloc(sizeof *node);
if (node != NULL) {
node -next = NULL;
node -data = malloc(sizeof *sample_data);
if (node -data != NULL) {
length = strlen(string);
sample_data = node -data;
sample_data -length = length;
sample_data -string = malloc(length);
if (sample_data -string != NULL) {
if (*head == NULL) {
*head = node;
} else {
tail -next = node;
}
memcpy(sample_data -string, string, length);
} else {
free(node -data);
free(node);
node = NULL;
}
} else {
free(node);
node = NULL;
}
}
return node;
}

void list_free(struct list_node *node, void (*free_data)(void *))
{
struct list_node *next_node;

while (node != NULL) {
next_node = node -next;
free_data(node -data);
free(node);
node = next_node;
}
}

void sample_free(void *data)
{
free(((struct sample *)data) -string);
free(data);
}

void sample_fprintf(struct list_node *node, FILE *stream)
{
struct sample s;
char *ptr;
size_t length;

while (node != NULL) {
s = *(struct sample *)(node -data);
fprintf(stream, "String length is %3u:",
(unsigned)s.length);
ptr = s.string;
length = s.length;
while (length-- != 0) {
putc(*ptr++, stream);
}
putc('\n', stream);
node = node -next;
}
}

/* END array_from_list.c */

--
pete
Dec 20 '06 #23

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Bruno R. Dias | last post by:
Perhaps it would be interesting to program a virtual machine simulating an ancient computer (such as the pdp-7). Then, it would be rather interesting to code for it (porting gcc to it maybe?). I...
12
by: rawrite | last post by:
I am just finishing watching a documentary about Rod Serling. It was cool, but after 20 minutes it got boring and all I wanted to do is subscribe to Net Flix and rent the Twilight Zone episodes....
3
by: Johnny Lee | last post by:
Hi, Look at the follow command in python command line, See what's interesting?:) >>> class A: i = 0 >>> a = A() >>> b = A() >>> a.i = 1 >>> print a.i, b.i
2
by: Dylan Phillips | last post by:
A strang error is occurring when I run the following code: SqlConnection c = new SqlConnection(); c.ConnectionString = "Initial Catalog=Northwind;user id=sa;password=kat1ie;Data Source=server";...
3
by: eBob.com | last post by:
Is there a namespace of interesting and important constants such as maximum length of a filename, maximum length of a path, maximum and minimum values which can be held by a Long (and other data...
8
by: Mythran | last post by:
Here is some code the provides some really interesting results! First, read over the two methods in class 'A' and compare. Just by looking at them, both results appear to return the EXACT same...
28
by: v4vijayakumar | last post by:
#include <string> #include <iostream> using namespace std; int main() { string str; str.resize(5); str = 't';
126
by: jacob navia | last post by:
Buffer overflows are a fact of life, and, more specifically, a fact of C. All is not lost however. In the book "Value Range Analysis of C programs" Axel Simon tries to establish a...
4
by: timer | last post by:
In the years past, there used to very interesting discussions in c.l.c But now, topics are not as interesting anymore. What happened?
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.