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