similar Perl data structure?

E

ela

Is there any similar structure in C that I can easily get the strings in a
file like:


Example file

bicycle
bus
ferry
plane
train


so I can print them generically? In Perl, I just read them into an array,
e.g. @vehicle

then get them back by foreach. Thanks for telling me if there's similar
handy function in C
 
G

Guest

Is there any similar structure in C that I can easily get the strings in a
file like:

Example file

bicycle
bus
ferry
plane
train

so I can print them generically? In Perl, I just read them into an array,
e.g. @vehicle

then get them back by foreach. Thanks for telling me if there's similar
handy function in C

the basic idea is the same but C is not suh a high level language
so you'll have to do more work.

Use fgets() to read lines from a file.
Then a for loop and printf() to print them.
You're going to have tp learn a bit of C todo this.
 
D

dfighter

ela said:
Is there any similar structure in C that I can easily get the strings in a
file like:


Example file

bicycle
bus
ferry
plane
train


so I can print them generically? In Perl, I just read them into an array,
e.g. @vehicle

then get them back by foreach. Thanks for telling me if there's similar
handy function in C
Hi ela!
No there is none as far as I know. Usually a problem like this (unknown
number of inputs) would be solved with a dynamic data structure like a
linked list, however even then you need to know some upper limit for the
length of each individual input (unless you want to keep reallocing ofc).
 
A

Antoninus Twink

Is there any similar structure in C that I can easily get the strings
in a file so I can print them generically? In Perl, I just read them
into an array, e.g. @vehicle then get them back by foreach. Thanks for
telling me if there's similar handy function in C

There's no single function, but it's easy enough to read them into an
array, then work through the array. Here's an example that uses the GNU
getline function, which simplifies life a bit by making big enough
buffers for the input lines under the hood.(*)

If you want to replicate a perl hash like %vehicle, you'll need to find
a library implementing a hash table, or do it yourself - C is a much
lower-level language than perl...

(*) If you're not using the GNU library, it's easy enough to write your
own getline function, or just look for the version by a regular poster
here, Eric Sossman. But beware that there is a troll who uses this group
to advertise his own getline routine, which he calls ggets. This is
poorly written and has many problems - avoid it.



#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(void)
{
char **vehicle = NULL;
size_t avehicle = 0, nvehicle = 0, i;
for(;;) {
if(nvehicle == avehicle) {
char **tmp;
avehicle = ((!avehicle * 500) + avehicle) << 1;
tmp = realloc(vehicle, avehicle * sizeof *vehicle);
if(!tmp) {
perror("malloc");
break;
}
vehicle = tmp;
}
vehicle[nvehicle] = NULL;
errno = 0;
if(getline(&vehicle[nvehicle], &i, stdin) == -1) {
if(errno)
perror("getline");
free(vehicle[nvehicle]);
break;
}
nvehicle++;
}
for(i=0; i<nvehicle; i++) {
printf("Vehicle %zu: %s", i, vehicle);
free(vehicle);
}
free(vehicle);
return 0;
}
 
J

jacob navia

ela said:
Is there any similar structure in C that I can easily get the strings in a
file like:


Example file

bicycle
bus
ferry
plane
train


so I can print them generically? In Perl, I just read them into an array,
e.g. @vehicle

then get them back by foreach. Thanks for telling me if there's similar
handy function in C
#include <stdio.h>
#include <stdlib.h>
#define LINSIZ 100
#ifndef __LCC__
// This program uses the fggets utility of C.B. Falconer. Here
// is the (slightly modified) code for people that do not use
// the lcc-win compiler or do not have it
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)
enum {OK = 0, NOMEM};
int EXPORT fggets(char* *ln, FILE *f)
{
int cursize, ch, ix;
char *buffer, *temp;

*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;
ix = 0;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
/* ran out of memory, return partial line */
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}
buffer[ix] = '\0';
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
*ln = buffer; /* without reducing it */
}
else *ln = temp;
return OK;
} /* fggets */
#endif

/*------------------------------------------------------------------------
Procedure: FileToArray
Purpose: Reads from the given file all the lines in it and
returns a pointer to an array of lines. In the given
int pointer returns the number of lines read, or an
error code if an error happened.
Input: Name of the file to process
Pointer to an integer that receives the number of
lines read or an error code, always negative
Output: A table of lines or NULL if error
Errors: -1 if file could not be opened, or a negative number
of lines if a memory error happened after reading
some lines
------------------------------------------------------------------------*/
char **FileToArray(char *file_name,int *linesread)
{
FILE *f = fopen(file_name,"r");
int line_counter=0,allocated_lines=0;
char **line_array=NULL,*linebuf=NULL;

*linesread = 0;
if (f == NULL) {
*linesread = -1;
return NULL;
}
while ((fggets(&linebuf,f)) == 0) {
if (line_counter >= allocated_lines) {
char **tmp = realloc(line_array,
sizeof(char *)*(line_counter+LINSIZ));
if (tmp == NULL) {
if (line_counter > 0)
line_counter = -line_counter;
break;
}
else line_array = tmp;
allocated_lines += LINSIZ;
}
line_array[line_counter++] = linebuf;
}
fclose(f);
*linesread = line_counter;
if (line_counter < allocated_lines) {
line_array = realloc(line_array,sizeof(char *)*line_counter);
}
return line_array;
}

#ifdef TEST
int main(int argc,char *argv[])
{
int lines;
char **plines;

if (argc < 2) {
return -1;
}
plines = FileToArray(argv[1],&lines);

if (plines) {
printf("%d lines\n---\n",lines);
for (int i=0; i<lines;i++) {
printf("%s\n",plines);
}
}
else {
if (lines == -1)
printf("file not found\n");
else printf("memory error after reading %d lines\n",-lines);
}
}
#endif
 
J

jacob navia

Antoninus said:
There's no single function, but it's easy enough to read them into an
array, then work through the array. Here's an example that uses the GNU
getline function, which simplifies life a bit by making big enough
buffers for the input lines under the hood.(*)

If you want to replicate a perl hash like %vehicle, you'll need to find
a library implementing a hash table, or do it yourself - C is a much
lower-level language than perl...

(*) If you're not using the GNU library, it's easy enough to write your
own getline function, or just look for the version by a regular poster
here, Eric Sossman. But beware that there is a troll who uses this group
to advertise his own getline routine, which he calls ggets. This is
poorly written and has many problems - avoid it.

Hi Antoninus

Sorry, I missed your code before I posted mine.
I am using fggets from Falconer, why do you think it has problems
or what problems you have experienced with it?

Thanks
 
I

Ian Collins

jacob said:
#include <stdio.h>
#include <stdlib.h>
#define LINSIZ 100
#ifndef __LCC__
// This program uses the fggets utility of C.B. Falconer. Here
// is the (slightly modified) code for people that do not use
// the lcc-win compiler or do not have it
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)
enum {OK = 0, NOMEM};
int EXPORT fggets(char* *ln, FILE *f)

What's EXPORT?

<snip>

Considering you hate C++, that was an awful lot of code to do what can
be done in less than 10 lines of C++!

:)
 
B

Ben Bacarisse

/*------------------------------------------------------------------------
Procedure: FileToArray
Purpose: Reads from the given file all the lines in it and
returns a pointer to an array of lines. In the given
int pointer returns the number of lines read, or an
error code if an error happened.
Input: Name of the file to process
Pointer to an integer that receives the number of
lines read or an error code, always negative
Output: A table of lines or NULL if error

This does not match the code. Some errors seem to return non-NULL and
some successful calls return NULL. For example your test program
prints "memory error after reading 0 lines" when the file is empty.
Errors: -1 if file could not be opened, or a negative number
of lines if a memory error happened after reading
some lines
------------------------------------------------------------------------*/
char **FileToArray(char *file_name,int *linesread)
{
FILE *f = fopen(file_name,"r");
int line_counter=0,allocated_lines=0;
char **line_array=NULL,*linebuf=NULL;

*linesread = 0;
if (f == NULL) {
*linesread = -1;
return NULL;
}
while ((fggets(&linebuf,f)) == 0) {
if (line_counter >= allocated_lines) {
char **tmp = realloc(line_array,
sizeof(char *)*(line_counter+LINSIZ));

You've copied ggets's design of using additive rather than
multiplicative growth. That seems odd to me. Why not multiply?
if (tmp == NULL) {
if (line_counter > 0)
line_counter = -line_counter;
break;

Trace through what will happen if this break is taken. You will try
to realloc with a size calculated from a negative int converted to
a size_t.
}
else line_array = tmp;
allocated_lines += LINSIZ;
}
line_array[line_counter++] = linebuf;
}
fclose(f);
*linesread = line_counter;
if (line_counter < allocated_lines) {
line_array = realloc(line_array,sizeof(char *)*line_counter);

I believe realloc is permitted to return NULL even when shrinking a
buffer. This would leak the allocated memory and return NULL even
though nothing has really gone wrong.
}
return line_array;
}

#ifdef TEST
int main(int argc,char *argv[])
{
int lines;
char **plines;

if (argc < 2) {
return -1;

Seems odd to use a non-portable return when the test program can only
succeed or fail.
}
plines = FileToArray(argv[1],&lines);

if (plines) {
printf("%d lines\n---\n",lines);
for (int i=0; i<lines;i++) {
printf("%s\n",plines);
}
}
else {
if (lines == -1)
printf("file not found\n");
else printf("memory error after reading %d lines\n",-lines);


I'd return a failure value here, rather than falling though to the
normal return.
 
B

BartC

Ian said:
What's EXPORT?

<snip>

Considering you hate C++, that was an awful lot of code to do what can
be done in less than 10 lines of C++!

In this newsgroup, any code using non-standard functions or macros must also
include the full source of those.

So you can imagine that any code which would be trivial (using your own
private library) is going to look bloated when posted here.
 
J

jacob navia

BartC said:
In this newsgroup, any code using non-standard functions or macros must
also include the full source of those.

So you can imagine that any code which would be trivial (using your own
private library) is going to look bloated when posted here.

Since I plan to put that in lcc-win standard library,
the code will be just

char **p = FileToCharArray("foo.txt",&lines);
 
I

Ian Collins

jacob said:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

void fileToArray( const char* fileName, vector<string>& lines )
{
ifstream in( fileName );

while( in ) {
string line;
getline( in, line );

if( !in.eof() ) {
lines.push_back(line);
}
}
}

The 10 lines is the fileToArray function.
 
J

jacob navia

Ian said:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

void fileToArray( const char* fileName, vector<string>& lines )
{
ifstream in( fileName );

while( in ) {
string line;
getline( in, line );

if( !in.eof() ) {
lines.push_back(line);
}
}
}

The 10 lines is the fileToArray function.

Sure. No error checking, not even returning a result. No provision for
out of memory errors, nor of returning the number of lines you have
read.

WONDERFUL!

Note that I could have reduced my line count by not including fggets
and the main function that shows how to use the software.

If you include a test function and error checking the line count is
about the same.

What is surely NOT the same is this:

dir filetoarray*.obj
Directory of D:\lcc\mc76\test

04/18/2009 11:33 PM 2,636 filetoarray.obj
04/19/2009 01:09 PM 308,477 filetoarray_cpp.obj

And both programs do the same thing

WONDERFUL!
 
I

Ian Collins

I posted in haste, the code was too long. It should have been

bool fileToArray( const char* fileName, vector<string>& lines )
{
ifstream in( fileName );
const bool ok = in.good();

if( ok ) {
string line;

while( getline( in, line ) ) {
lines.push_back(line);
}
}
return ok;
}
Still 10 lines, but with a check for file not existing.
Sure. No error checking, not even returning a result.

It did return a result, lines is a reference.
No provision for out of memory errors

The standard library does that, an exception will be thrown.
nor of returning the number of lines you have read.

The length of the vector.
WONDERFUL!

I know, it is, isn't it?
Note that I could have reduced my line count by not including fggets
and the main function that shows how to use the software.

I stuck to standard library functions.
If you include a test function and error checking the line count is
about the same.

Nope, as you can see, the line count for fileToArray remains at 10, with
the extra error check.

The main function (with exception handling) is about the same size:

int main(int argc, char *argv[])
{
if (argc < 2) {
return -1;
}

vector<string> lines;

try{
if( fileToArray( argv[1], lines ) ) {
for( unsigned n = 0; n < lines.size(); ++n ) {
cout << lines[n] << endl;
}
cout << lines.size() << " lines" << endl << "---" << endl;
}
else {
cerr << "file not found:" << argv[1] << endl;
}
}
catch( const exception& e ) {
cerr << e.what() << endl;
}
}
What is surely NOT the same is this:

dir filetoarray*.obj
Directory of D:\lcc\mc76\test

Did I say it was?
 
J

jacob navia

The problem with C is not the language itself.

It is the lack of any higher level, standardized interfaces.
I have discussed this very often here, and the principal problem is
that the standards committee refuses any progress in this direction,
maintaining the language at a primitive level so that people
like you can say

Look, how wonderful my bloated language is!

If we would have a simple

getline()

function in the standard, we wouldn't have to rewrite each time
a new one.

But introducing such a function is beyond what the standards committee
wants, to keep C++ "THE" language to use.
 
J

jacob navia

William said:
Sigh. Really, do you really rewrite it each time you need it?
I thought that just in this thread you mentioned using CBF's
ggets. Clearly you understand the concept of libraries.
Why do you insist on perpetuating the ridiculous idea
that people "rewrite each time".

Because the library is not available,
because the project doesn't want to use public
domain source code for copyright reasons,
and for many other reasons
Perhaps you are upset
that because something like getline isn't in the standard
library, each development team is required
to either implement it or find another non-standard
implementation, but they don't need to do it each time.
They need to do it exactly once, and then re-use that
library. Surely you grasp that concept.

But then, each application has its own different
getline().

And there is also GNU getline() that many applications use,
etc etc. What I am saying is that all this wouldn't be necessary
if we would have a STANDARD way of doing such a simple thing!
 
K

Keith Thompson

jacob navia said:
Because the library is not available,
because the project doesn't want to use public
domain source code for copyright reasons,
and for many other reasons
[...]

I'm just going to address this one point:

What "copyright reasons" could there be for not wanting to use public
domain source code? (Note that "public domain" is not the same as
"open source".)
 
J

jacob navia

Keith said:
jacob navia said:
Because the library is not available,
because the project doesn't want to use public
domain source code for copyright reasons,
and for many other reasons
[...]

I'm just going to address this one point:

What "copyright reasons" could there be for not wanting to use public
domain source code? (Note that "public domain" is not the same as
"open source".)

Many. If you are selling your sources, you can't sell
that part. And most of those "reasons" are just paranoia from
managers that do not understand all legal issues involved and do
not want to take any risks.
 
K

Keith Thompson

jacob navia said:
Keith said:
Because the library is not available,
because the project doesn't want to use public
domain source code for copyright reasons,
and for many other reasons
[...]

I'm just going to address this one point:

What "copyright reasons" could there be for not wanting to use public
domain source code? (Note that "public domain" is not the same as
"open source".)

Many. If you are selling your sources, you can't sell
that part.

Why not?

[...]
 
J

jacob navia

Keith said:
jacob navia said:
Keith said:
Because the library is not available,
because the project doesn't want to use public
domain source code for copyright reasons,
and for many other reasons
[...]

I'm just going to address this one point:

What "copyright reasons" could there be for not wanting to use public
domain source code? (Note that "public domain" is not the same as
"open source".)
Many. If you are selling your sources, you can't sell
that part.

Why not?

[...]

Obviously because they are in the public domain!
 

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,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top