Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Reading a table

Reply
Thread Tools

Reading a table

 
 
Stephen.Schoenberger@gmail.com
Guest
Posts: n/a
 
      11-26-2007
Hello,

My C is a bit rusty (.NET programmer normally but need to do this in
C) and I need to read in a text file that is setup as a table. The
general form of the file is

00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000

I need to read the file line by line and eventually parse out each
piece of the file and store in arrays that correspond to the specific
line. array1[1] would be the first entry in the first line and so on
and so forth.

Any suggestions would be great!

Thanks.
 
Reply With Quote
 
 
 
 
user923005
Guest
Posts: n/a
 
      11-26-2007
On Nov 26, 11:04 am, (E-Mail Removed) wrote:
> Hello,
>
> My C is a bit rusty (.NET programmer normally but need to do this in
> C) and I need to read in a text file that is setup as a table. The
> general form of the file is
>
> 00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000
>
> I need to read the file line by line and eventually parse out each
> piece of the file and store in arrays that correspond to the specific
> line. array1[1] would be the first entry in the first line and so on
> and so forth.
>
> Any suggestions would be great!


fopen() to open the file.
fgets() to read in one line at a time.
write your own function to parse it, because only you know the format.

HTH
 
Reply With Quote
 
 
 
 
Stephen.Schoenberger@gmail.com
Guest
Posts: n/a
 
      11-26-2007
On Nov 26, 2:10 pm, user923005 <(E-Mail Removed)> wrote:
> On Nov 26, 11:04 am, (E-Mail Removed) wrote:
>
> > Hello,

>
> > My C is a bit rusty (.NET programmer normally but need to do this in
> > C) and I need to read in a text file that is setup as a table. The
> > general form of the file is

>
> > 00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000

>
> > I need to read the file line by line and eventually parse out each
> > piece of the file and store in arrays that correspond to the specific
> > line. array1[1] would be the first entry in the first line and so on
> > and so forth.

>
> > Any suggestions would be great!

>
> fopen() to open the file.
> fgets() to read in one line at a time.
> write your own function to parse it, because only you know the format.
>
> HTH


Thanks!
 
Reply With Quote
 
Default User
Guest
Posts: n/a
 
      11-26-2007
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

> Hello,
>
> My C is a bit rusty (.NET programmer normally but need to do this in
> C) and I need to read in a text file that is setup as a table. The
> general form of the file is
>
> 00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000
>
> I need to read the file line by line and eventually parse out each
> piece of the file and store in arrays that correspond to the specific
> line. array1[1] would be the first entry in the first line and so on
> and so forth.
>
> Any suggestions would be great!


Arrays in C are indexed from 0. You can leave the first one empty if
you're determined to have 1-based indexing, but it's not an overly good
idea.

I'd also suggest a two-dimensional array, rather than separate ones
named "array1" etc. That makes for easier handling, as the entire table
OR individual rows can be passed to functions or whatever. So the first
row would be table[0], and the first element would be table[0][0].

It's especially easy if you happen to know the number of rows and
columns going in, otherwise you'll probably need a dynamic array. Of
course, you still need to come up with a data type for the elements
themselves, presumably char*, but it's not clear what the parsing
actually consists of. We'd need more information.




Brian
 
Reply With Quote
 
Bill Reid
Guest
Posts: n/a
 
      11-27-2007

<(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> On Nov 26, 2:10 pm, user923005 <(E-Mail Removed)> wrote:
> > On Nov 26, 11:04 am, (E-Mail Removed) wrote:
> >
> > > Hello,

> >
> > > My C is a bit rusty (.NET programmer normally but need to do this in
> > > C) and I need to read in a text file that is setup as a table. The
> > > general form of the file is

> >
> > > 00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000

> >
> > > I need to read the file line by line and eventually parse out each
> > > piece of the file and store in arrays that correspond to the specific
> > > line. array1[1] would be the first entry in the first line and so on
> > > and so forth.

> >
> > > Any suggestions would be great!

> >
> > fopen() to open the file.
> > fgets() to read in one line at a time.
> > write your own function to parse it, because only you know the format.
> >
> > HTH

>
> Thanks!


He forgot to tell you about fclose()!

Anyway...

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

#define LINEMAX 512

extern unsigned
assign_text_file_line_fields
(char *,unsigned (*)(unsigned,char *,void *),void *);

static FILE *text_file;

static char text_line[LINEMAX];

/* assigns field values from text file lines using callback function */
unsigned assign_text_file_line_fields
(char *text_file_path,
unsigned assign_func(unsigned,char *,void *),void *assign_ptr) {
unsigned line_num=0;
ret_val=FALSE;

/* try to open text file, return if failure */
if((text_file=fopen(text_file_path,"rt"))==NULL) {
printf("\nERROR: Could not open text file\n%s",
text_file_path);
goto EXIT_FUNCTION;
}

/* get every line in file, pass to callback function */
while((fgets(text_line,LINEMAX,text_file))!=NULL) {

if(!assign_func(line_num,text_line,assign_ptr)) {
printf("ERROR: Could not assign line %d fields);
goto CLOSE_TEXT_FILE;
}

line_num++;
}

/* OK, looks like we've succeeded */
ret_val=TRUE;

/* try to close file, warn if failure */
CLOSE_TEXT_FILE :
if((fclose(db_init_file))==EOF)
printf("\nWARNING: Problem closing text file\n%s",
text_file_path);

/* buh-bye */
EXIT_FUNCTION :
return ret_val;
}

If you set up the above in its own little object file/library or
whatever, you can link it into any program when you need to
parse any type of text file with regularly-formatted lines of
column-data, by writing a specific assign_func for each type
of file, and declaring a suitable multi-dimensional array (or
array of structs) to hold the data:

typedef struct My_Data {
double field_1;
unsigned field_2;
int field_3;
} My_Data;

My_Data my_data_array[100];

My_Data *my_data_array_ptr=&my_data_array;

static unsigned
assign_my_file_fields
(unsigned line_num,char *text_line,void *data_ptr) {
My_Data *my_data_ptr=data_ptr;
my_data_ptr+=line_num;

/* line parsing and assigning goes here */

}

assign_text_file_line_fields
(text_file_path,assign_my_file_fields,(void *)(my_data_array_ptr));

And you'll never have to write the file opening, reading, and closing
code ever again...the only reason I bring this up is because, of course,
I have literally hundreds of different text file formats to read in my
own code...

---
William Ernest Reid



 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      11-29-2007
(E-Mail Removed) wrote:
>
> Hello,
>
> My C is a bit rusty (.NET programmer normally but need to do this in
> C) and I need to read in a text file that is setup as a table. The
> general form of the file is
>
> 00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000
>
> I need to read the file line by line and eventually parse out each
> piece of the file and store in arrays that correspond to the specific
> line. array1[1] would be the first entry in the first line and so on
> and so forth.


/* BEGIN file_parse.c output */

Input file:
0000000000 USNIST00Z 00000000_00 8 318 318 068 9318 068
0000000001 USNIST00Z 00000000_00 9 619 119 119 7619 119
0000000002 USNIST00Z 00000000_00 2 252 252 002 6252 002

Resulting array:
array[0][0] 0000000000
array[0][1] USNIST00Z
array[0][2] 00000000_00
array[0][3] 8
array[0][4] 318
array[0][5] 318
array[0][6] 068
array[0][7] 9318
array[0][8] 068


array[1][0] 0000000001
array[1][1] USNIST00Z
array[1][2] 00000000_00
array[1][3] 9
array[1][4] 619
array[1][5] 119
array[1][6] 119
array[1][7] 7619
array[1][8] 119


array[2][0] 0000000002
array[2][1] USNIST00Z
array[2][2] 00000000_00
array[2][3] 2
array[2][4] 252
array[2][5] 252
array[2][6] 002
array[2][7] 6252
array[2][8] 002


/* END file_parse.c output */


/* BEGIN file_parse.c */
/*
My C is a bit rusty
(.NET programmer normally but need to do this in C)
and I need to read in a text file that is setup as a table.
The general form of the file is

00000000 USNIST00Z 00000000_00 0 000 000 000 0000 000

I need to read the file line by line and eventually parse out each
piece of the file and store in arrays that correspond to the specific
line. array1[1] would be the first entry in the first line and so on
and so forth.
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

#define LINES_PER_FILE 3
#define LU_RAND_SEED 123456789LU
#define LU_RAND(S) ((S) * 69069 + 362437 & 0XFFFFFFFFLU)
#define NMEMB(A) (sizeof (A) / sizeof *(A))

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

typedef struct list_node list_type;

int get_line(char **lineptr, size_t *n, FILE *stream);
int list_fputs(list_type *node, FILE *stream);
list_type *list_append(list_type **head,
list_type *tail,
void *data,
size_t size);
void list_free(list_type *node, void (*free_data)(void *));
void no_free(void *data);
void free_ptrs(char ***p, size_t nmemb);
void display_array(char ***p, size_t nmemb, size_t n_fields);

int main(void)
{
long unsigned lu_seed, line, n_fields, field;
int rc;
char *buff, *ptr;
size_t size;
list_type *tail, *head;
char fn[L_tmpnam];
FILE *fp;
char ***f;

puts("/* BEGIN file_parse.c output */");
/*
** Open temporary input text file for writing.
*/
lu_seed = LU_RAND_SEED;
tmpnam(fn);
fp = fopen(fn, "w");
if (fp == NULL) {
fputs("fopen(fn), \"w\") == NULL\n", stderr);
exit(EXIT_FAILURE);
}
for (line = 0; line != LINES_PER_FILE; ++line) {
lu_seed = LU_RAND(lu_seed);
fprintf(fp,
"%.10lu %s %.1lu %.3lu %.3lu %.3lu %.4lu %.3lu\n",
line, "USNIST00Z 00000000_00",
lu_seed % 10, lu_seed % 1000,
lu_seed % 500, lu_seed % 250,
lu_seed % 10000, lu_seed % 125);
}
/*
** Close file.
*/
fclose(fp);
/*
** Open input text file for reading.
** Represent each line of the input text file
** as a string in a node of a linked list.
** Close temp input file after reading.
*/
size = 0;
buff = NULL;
head = tail = NULL;
fp = fopen(fn, "r");
if (fp == NULL) {
remove(fn);
fputs("fopen(fn), \"r\") == NULL\n", stderr);
exit(EXIT_FAILURE);
}
while ((rc = get_line(&buff, &size, fp)) > 0) {
tail = list_append(&head, tail, buff, strlen(buff) + 1);
if (tail == NULL) {
fputs("tail == NULL\n", stderr);
break;
}
}
fclose(fp);
/*
** Free allocated buffer used by get_line function.
** Remove temporary input file.
*/
free(buff);
remove(fn);
if (rc != EOF) {
list_free(head, free);
fprintf(stderr, "rc == %d\n", rc);
exit(EXIT_FAILURE);
}
/*
** Display linked list.
*/
puts("\nInput file:");
list_fputs(head, stdout);
/*
** Create array.
*/
n_fields = 1;
for (ptr = head -> data; *ptr != '\0'; ++ptr) {
if (*ptr == ' ') {
++n_fields;
}
}
f = malloc(line * sizeof *f);
if (f == NULL) {
list_free(head, free);
fputs("f == NULL\n", stderr);
exit(EXIT_FAILURE);
}
for (line = 0; line != LINES_PER_FILE; ++line) {
f[line] = malloc(n_fields * sizeof *f[line]);
if (f[line] == NULL) {
puts("f[line] == NULL");
exit(EXIT_FAILURE);
}
}
/*
** Tokenise list data and
** assign string addresses to pointers in array.
*/
line = 0;
for (tail = head; tail != NULL; tail = tail -> next) {
f[line][0] = tail -> data;
for (field = 1; field != n_fields; ++field) {
f[line][field] = strchr(f[line][field - 1], ' ');
if (f[line][field] == NULL) {
puts("f[line][field] == NULL");
exit(EXIT_FAILURE);
}
*f[line][field]++ = '\0';
}
++line;
}
/*
** Free list nodes but not node->data.
*/
list_free(head, no_free);
/*
** Display resulting array.
*/
puts("\nResulting array:");
display_array(f, LINES_PER_FILE, n_fields);
/*
** Free array.
*/
free_ptrs(f, LINES_PER_FILE);
free(f);
puts("/* END file_parse.c output */");
return 0;
}

void display_array(char ***p, size_t nmemb, size_t n_fields)
{
long unsigned line, field;

for (line = 0; line != nmemb; ++line) {
for (field = 0; field != n_fields; ++field) {
printf("array[%lu][%lu] %s\n",
line, field, p[line][field]);
}
puts("\n");
}
}

void free_ptrs(char ***p, size_t nmemb)
{
while (nmemb-- != 0) {
free(p[nmemb]);
}
}

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

count = 0;
while ((rc = getc(stream)) != EOF) {
if (count != (size_t)-2) {
++count;
}
if ((size_t)(count + 2u) > *n) {
p = realloc(*lineptr, count + 2);
if (p == NULL) {
if (*n > count) {
if (rc != '\n') {
(*lineptr)[count] = '\0';
(*lineptr)[count - 1] = (char)rc;
} else {
(*lineptr)[count - 1] = '\0';
}
} else {
if (*n != 0) {
**lineptr = '\0';
}
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 = INT_MAX > count ? count : INT_MAX;
} else {
if (*n > count) {
(*lineptr)[count] = '\0';
}
}
return rc;
}

int list_fputs(list_type *node, FILE *stream)
{
while (node != NULL) {
if (fputs(node -> data, stream) == EOF) {
return EOF;
}
if (putc('\n', stream) == EOF) {
return EOF;
}
node = node -> next;
}
return '\n';
}

list_type *list_append(list_type **head,
list_type *tail,
void *data,
size_t size)
{
list_type *node;

node = malloc(sizeof *node);
if (node != NULL) {
node -> next = NULL;
node -> data = malloc(size);
if (node -> data != NULL) {
memcpy(node -> data, data, size);
if (*head != NULL) {
tail -> next = node;
} else {
*head = node;
}
} else {
free(node);
node = NULL;
}
}
return node;
}

void list_free(list_type *node, void (*free_data)(void *))
{
list_type *next_node;

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

void no_free(void *data)
{
data;
}

/* END file_parse.c */


--
pete
 
Reply With Quote
 
pete
Guest
Posts: n/a
 
      11-29-2007
pete wrote:

> /* BEGIN file_parse.c */


I rewrote some of the code.

> long unsigned lu_seed, line, n_fields, field;


Could use another variable to count file lines.

long unsigned lu_seed, line, n_lines, n_fields, field;

> for (line = 0; line != LINES_PER_FILE; ++line) {
> f[line] = malloc(n_fields * sizeof *f[line]);
> if (f[line] == NULL) {
> puts("f[line] == NULL");
> exit(EXIT_FAILURE);
> }
> }


Some of the cleanup could be better.

for (line = 0; line != n_lines; ++line) {
f[line] = malloc(n_fields * sizeof *f[line]);
if (f[line] == NULL) {
free_ptrs(f, line);
list_free(head, free);
puts("f[line] == NULL");
exit(EXIT_FAILURE);
}
f[line][0] = NULL;
}

> if (f[line][field] == NULL) {
> puts("f[line][field] == NULL");
> exit(EXIT_FAILURE);
> }


if (f[line][field] == NULL) {
free_ptrs(f, n_lines);
list_free(head, free);
puts("f[line][field] == NULL");
exit(EXIT_FAILURE);


> free_ptrs(f, LINES_PER_FILE);
> free(f);


Instead of the above two lines, just this one:

free_ptrs(f, n_lines);



> void free_ptrs(char ***p, size_t nmemb)
> {
> while (nmemb-- != 0) {
> free(p[nmemb]);
> }
> }


This version of free_ptrs, frees the list data,
which I had neglected to do before.

void free_ptrs(char ***p, size_t nmemb)
{
while (nmemb-- != 0) {
free(p[nmemb][0]);
free(p[nmemb]);
}
free(p);
}

--
pete
 
Reply With Quote
 
Roland Pibinger
Guest
Posts: n/a
 
      11-29-2007
On Tue, 27 Nov 2007 02:19:55 GMT, "Bill Reid" wrote:
>Anyway...
>
>#include <stdio.h>
>#include <stdlib.h>
>
>#define LINEMAX 512
>
>extern unsigned
>assign_text_file_line_fields
>(char *,unsigned (*)(unsigned,char *,void *),void *);
>
>static FILE *text_file;
>
>static char text_line[LINEMAX];
>
>/* assigns field values from text file lines using callback function */
>unsigned assign_text_file_line_fields
>(char *text_file_path,
>unsigned assign_func(unsigned,char *,void *),void *assign_ptr) {
> unsigned line_num=0;
> ret_val=FALSE;
>
> /* try to open text file, return if failure */
> if((text_file=fopen(text_file_path,"rt"))==NULL) {
> printf("\nERROR: Could not open text file\n%s",
> text_file_path);
> goto EXIT_FUNCTION;
> }
>
> /* get every line in file, pass to callback function */
> while((fgets(text_line,LINEMAX,text_file))!=NULL) {
>
> if(!assign_func(line_num,text_line,assign_ptr)) {
> printf("ERROR: Could not assign line %d fields);
> goto CLOSE_TEXT_FILE;
> }
>
> line_num++;
> }
>
> /* OK, looks like we've succeeded */
> ret_val=TRUE;
>
> /* try to close file, warn if failure */
> CLOSE_TEXT_FILE :
> if((fclose(db_init_file))==EOF)
> printf("\nWARNING: Problem closing text file\n%s",
> text_file_path);
>
> /* buh-bye */
> EXIT_FUNCTION :
> return ret_val;
> }


Your callback solution has its merits. But you could have done it

- without gotos
- whithout static FILE
- for arbitrary long lines (no hard-coded maximum line lenght)
- with a typedef for the callback function for better readability
- with an explanation for "rt" instead of "r"
- returning error codes instead of using printfs
- with self-explanatory names e.g. process_file_by_line (insted of
assign_text_file_line_fields), process_line (instead of assign_func),
data or context (instead of assign_ptr)



--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch
 
Reply With Quote
 
Bill Reid
Guest
Posts: n/a
 
      11-30-2007

Roland Pibinger <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> On Tue, 27 Nov 2007 02:19:55 GMT, "Bill Reid" wrote:
> >Anyway...
> >
> >#include <stdio.h>
> >#include <stdlib.h>
> >
> >#define LINEMAX 512
> >
> >extern unsigned
> >assign_text_file_line_fields
> >(char *,unsigned (*)(unsigned,char *,void *),void *);
> >
> >static FILE *text_file;
> >
> >static char text_line[LINEMAX];
> >
> >/* assigns field values from text file lines using callback function */
> >unsigned assign_text_file_line_fields
> >(char *text_file_path,
> >unsigned assign_func(unsigned,char *,void *),void *assign_ptr) {
> > unsigned line_num=0;
> > ret_val=FALSE;
> >
> > /* try to open text file, return if failure */
> > if((text_file=fopen(text_file_path,"rt"))==NULL) {
> > printf("\nERROR: Could not open text file\n%s",
> > text_file_path);
> > goto EXIT_FUNCTION;
> > }
> >
> > /* get every line in file, pass to callback function */
> > while((fgets(text_line,LINEMAX,text_file))!=NULL) {
> >
> > if(!assign_func(line_num,text_line,assign_ptr)) {
> > printf("ERROR: Could not assign line %d fields);
> > goto CLOSE_TEXT_FILE;
> > }
> >
> > line_num++;
> > }
> >
> > /* OK, looks like we've succeeded */
> > ret_val=TRUE;
> >
> > /* try to close file, warn if failure */
> > CLOSE_TEXT_FILE :
> > if((fclose(db_init_file))==EOF)
> > printf("\nWARNING: Problem closing text file\n%s",
> > text_file_path);
> >
> > /* buh-bye */
> > EXIT_FUNCTION :
> > return ret_val;
> > }

>
> Your callback solution has its merits. But you could have done it
>
> - without gotos


They're worth it just to irritate some people and don't hurt
anything...

> - whithout static FILE


Possibly, but the idea here is just to read a single file and
then close it right up...

> - for arbitrary long lines (no hard-coded maximum line lenght)


Yes, but again the idea here is we KNOW the maximum size
of our file lines, almost certainly because we wrote them in the
first place with trusted and checked data (note that I left out anything
about sizing the array for the number of lines, that's left "up to the
reader")...in real life, I do have a similar function that does dynamic
resizing for arbitrarily long lines for other types of files...

> - with a typedef for the callback function for better readability


Uh, yeah, maybe, I'm not sure I'm following you here...

> - with an explanation for "rt" instead of "r"


Read the friggin' man page!

> - returning error codes instead of using printfs


Up to the original poster to implement their error handling
routines; actually, I use something else in "real life" but modified
it for "readability"...

> - with self-explanatory names e.g. process_file_by_line (insted of
> assign_text_file_line_fields), process_line (instead of assign_func),
> data or context (instead of assign_ptr)


Yeah, semantics, maybe...

> "The best software is simple, elegant, and full of drama" - Grady Booch


Ah, brinksmanship, most applicable to nuclear power plant software...

---
William Ernest Reid



 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      11-30-2007
Bill Reid wrote:
> Roland Pibinger <(E-Mail Removed)> wrote in message
>

.... snip ...
>
>> - whithout static FILE

>
> Possibly, but the idea here is just to read a single file and
> then close it right up...
>
>> - for arbitrary long lines (no hard-coded maximum line lenght)

>
> Yes, but again the idea here is we KNOW the maximum size> of our
> file lines,


However, some people want to copy files without worrying about line
length. With ggets (and fggets) you can handle this with ease, as
in the following:

[1] c:\c\junk>cc -o fcopylns.exe ggets.o junk.c

[1] c:\c\junk>fcopylns <junk.c
#include <stdio.h>
#include <stdlib.h>
#include "ggets.h"

int main(void) {
char *line;

while (0 == ggets(&line)) {
puts(line);
free(line);
}
return 0;
} /* main, fcopylns */

Note the complexity. You can get the source etc. for ggets at:

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

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.



--
Posted via a free Usenet account from http://www.teranews.com

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
UnauthorizedAccessException when reading XML files (no problem when reading other file-types) blabla120@gmx.net ASP .Net 0 09-15-2006 02:08 PM
ASP.NET Reading problem (reading .xls) Wael Soliman ASP .Net 2 01-03-2005 05:33 PM
reading the DB vs. reading a text file...performance preference? Darrel ASP .Net 3 11-11-2004 02:27 PM
Table/table rows/table data tag question? Rio HTML 4 11-05-2004 08:11 AM
Could not load type VTFixup Table from assembly Invalid token in v-table fix-up table. David Williams ASP .Net 2 08-12-2003 07:55 AM



Advertisments