Proper fgets

U

uidzer0

Hey everyone,

Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?

#include <stdio.h>
#include <errno.h>

int main(int argc, char **argv) {
FILE *fp;
char line[4096];

if(argc < 2) {
printf("usage: %s <file>\n", argv[0]);
return(1);
}

if((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");
return(1);
}

while(fgets(line, sizeof(line), fp)) {
printf("%s", line);
}

return(0);
}
 
U

user923005

Hey everyone,

Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?

#include <stdio.h>
#include <errno.h>

int main(int argc, char **argv) {
FILE *fp;
char line[4096];

if(argc < 2) {
printf("usage: %s <file>\n", argv[0]);
return(1);
}

if((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");
return(1);
}

while(fgets(line, sizeof(line), fp)) {
printf("%s", line);
}

return(0);



}- Hide quoted text -

- Show quoted text -

Do a web search for getline
 
U

uidzer0

That's perfect, however, it appears to be a GNU extension. Is there a
ANSI C way to do this?

Thanks again,

Ben

Hey everyone,
Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv) {
FILE *fp;
char line[4096];
if(argc < 2) {
printf("usage: %s <file>\n", argv[0]);
return(1);
}
if((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");
return(1);
}
while(fgets(line, sizeof(line), fp)) {
printf("%s", line);
}

}- Hide quoted text -
- Show quoted text -

Do a web search for getline
 
S

santosh

uidzer0 said:
Hey everyone,

Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?

#include <stdio.h>
#include <errno.h>

int main(int argc, char **argv) {
FILE *fp;
char line[4096];

if(argc < 2) {
printf("usage: %s <file>\n", argv[0]);

argv[0] need not point to the program's invocation name. Some
environments do not provide this information.
return(1);

This is a non-portable return values. The portable ones are 0 and
EXIT_SUCCESS to indicate success and EXIT_FAILURE to indicate abnormal
termination. For both the macros, stdlib.h must be included.
}

if((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");

fopen is not guaranteed to set errno. It's a quality-of-implementation
issue.
return(1);
}

while(fgets(line, sizeof(line), fp)) {
printf("%s", line);

You should include a newline to immediately flush the output to the
connected device.
}

return(0);

Parenthesis not necessary.

Now coming to your main question, yes, the most portable method to do
what you want is to use malloc to allocate an array which you can
resize, with realloc, on the fly, as you read in more input.
CBFalconer often posts the sources for his 'ggets' function to do
exactly what you want.

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

Note: C99 has also introduced Variable Length Arrays, (VLA), which can
do what you want in a syntactically clean form, but this is poorly
implemented by most compilers and has a serious problem in that an
allocation failure leads to undefined behaviour, with no way of
detection.
 
U

uidzer0

uidzer0 said:
Hey everyone,
Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv) {
FILE *fp;
char line[4096];
if(argc < 2) {
printf("usage: %s <file>\n", argv[0]);

argv[0] need not point to the program's invocation name. Some
environments do not provide this information.
return(1);

This is a non-portable return values. The portable ones are 0 and
EXIT_SUCCESS to indicate success and EXIT_FAILURE to indicate abnormal
termination. For both the macros, stdlib.h must be included.
if((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");

fopen is not guaranteed to set errno. It's a quality-of-implementation
issue.
return(1);
}
while(fgets(line, sizeof(line), fp)) {
printf("%s", line);

You should include a newline to immediately flush the output to the
connected device.
return(0);

Parenthesis not necessary.

Now coming to your main question, yes, the most portable method to do
what you want is to use malloc to allocate an array which you can
resize, with realloc, on the fly, as you read in more input.
CBFalconer often posts the sources for his 'ggets' function to do
exactly what you want.

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

Note: C99 has also introduced Variable Length Arrays, (VLA), which can
do what you want in a syntactically clean form, but this is poorly
implemented by most compilers and has a serious problem in that an
allocation failure leads to undefined behaviour, with no way of
detection.

Perfect, thanks.
 
E

Eric Sosman

uidzer0 said:
Hey everyone,

Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?

#include <stdio.h>
#include <errno.h>

int main(int argc, char **argv) {
FILE *fp;
char line[4096];

if(argc < 2) {
printf("usage: %s <file>\n", argv[0]);
return(1);
}

if((fp = fopen(argv[1], "r")) == NULL) {
perror("fopen");
return(1);
}

while(fgets(line, sizeof(line), fp)) {
printf("%s", line);
}

return(0);
}

The allocation looks fine as it stands, since the program
works even if line[] holds just a fragment of a line instead
of an entire line. The code could be improved in a number of
small ways, but there's nothing irretrievably wrong with it.
 
M

Mark McIntyre

That's perfect, however, it appears to be a GNU extension. Is there a
ANSI C way to do this?

Look at the source for getline() ?
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
O

Old Wolf

uidzer0 said:
Taken the following code; is there a "proper" or dynamic way to
allocate the length of line[]?

while(fgets(line, sizeof(line), fp)) {
printf("%s", line);

Now coming to your main question, yes, the most portable method to do
what you want is to use malloc to allocate an array which you can
resize, with realloc, on the fly, as you read in more input.

Note: C99 has also introduced Variable Length Arrays, (VLA), which can
do what you want in a syntactically clean form

I don't see how VLA can be used to solve this problem. The VLA
must be declared with a size, which cannot be altered subsequently.
 
C

Chris Torek

uidzer0 wrote:
[edited slightly, and trimmed heavily]
You should include a newline to immediately flush the output to the
connected device.

Actually, in this case, there *is* an included newline (usually):
it is in the string stored in "line". Remember that fgets()
keeps the newline at the end of the input line. There are only
two cases in which the newline is omitted:

1) The input line was so long that it had to be split. The
fgets() function writes the initial part of the input
line into the array ("line", in this case), and leaves
the remaining part of the input line in the input stream.[%]
Subsequent fgets() calls will read and consume more of
that line, up to and including the newline that terminates
it. Those partial-and-eventually-complete lines (including
the single terminating newline) will be passed to the
printf() call, so the output will re-construct the original
input.

2) The input file ended without a terminating newline, and the
underlying implementation chooses to handle such files by
reporting the final line without a terminating newline. In
this case, the next fgets() call will return NULL, with the
reason for failure being "reached end of file" (i.e., this
will set feof(fp)). In this case, it is usually probably best
to output an unterminated text line, so as to mimic the input.
There is no guarantee that the implementation will be able
to produce that output line (perhaps the input file is
coming from a file system that supports partial final lines,
while the output file is being written on one that does
not), but unless you have something specific in mind, adding
a newline terminator (to make the output "valid") is, at the
least, changing the input. :)

So in this *particular* case -- reading an input file and copying
it to the standard output -- using printf with "%s" and no newline
is probably right. (Or, equivalently, one can use fputs(line,stdout)
in the loop body. The fputs() and puts() functions have the same
newline relationship, in this case, as the fgets() and gets()
functions: the old, less-thought-out, less-usable[$] gets() and
puts() fiddle with the data, while the newer, more-thought-out
fgets() and fputs() functions leave it unchanged, as much as
possible. In less precise, but more memorable, words, "gets and
puts delete and add a newline respectively; fgets and fputs do
not.")

-----
[%] This assumes the implementation is actually capable of handling
very long lines. Text files, on some systems, have line length
restrictions. If the line[] array has size 4096, but the
underlying system never has lines longer than 1023 characters,
there can never be a line long enough to split. In some
particularly old and klunky systems, it is even possible that
the input file might have lines longer than the input methods
can handle, in which case overlong input lines might be truncated
before the C system ever really "sees" them. In both cases, the
C compiler is effectively hobbled by the system. There is no
portable way around this problem, though, so one might as well
ignore it, in general. (In specific cases, one might be able
to open the text file as a "binary" file and decode the "true
intent" from the raw record-data. If the raw data is encoded
-- e.g., some form of ISAM or VSAM -- doing this can be rather
complex.)

[$] In the case of gets(), "nearly unusable". While its newline
removal is sometimes handy, you can only use it safely if you
can somehow verify the input data before reading it. On some
systems you could do a pre-scan of the entire file, with the
file somehow locked against changes, but this is nonportable
and, if not a bad idea for other reasons, at the least, I would
call it "icky". :) One might as well just use fgets(), or
code similar to Chuck Falconer's ggets(), or some such.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top