PDA

View Full Version : Read file, Write to stdout in C



DrSammyD
September 10th, 2009, 02:29 AM
Hi, I just installed ubuntu in order to program in C and I'm having a problem with this code.

I'm trying to read a file passed using a name passed in as an argument from the terminal, and write that file to the stdout.

Should this code work?


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

main(int argc, char **argv)
{
int n, fd;
char buf[5];
int count = 0;
while(count < 1)
{
if(fd = open(argv[count], O_RDONLY)>0)
{
count++;
n= read(fd, buf, 5);
if (write(1,buf,n) != n)
printf("write error");

if (n < 0)
printf("read error");
}
else
printf("Unable to open file");
}

exit(0);
}
Or am I just a moron at programming in C?

PmDematagoda
September 10th, 2009, 03:16 AM
Could you please first put your code into Code tags, indent them properly and address these small problems as well:-
1) main does not have a type specified for it, this is not allowed as the implicit int rule is no longer as of C99, you have to specify a type, preferably int.

2) You are ending the program with an exit(), why not use return for something like that?

3) argv[count] is not a sensible file to open since it is a binary file(the executable of the program which is running it itself since count is 0), so you will get rubbish, give it a more sensible file like the Xorg file at /var/log/Xorg.0.log or similar as a reference.

DrSammyD
September 10th, 2009, 03:39 AM
So how do I get it to write out to the screen? what is the file descriptor for stdout? isn't it 1?


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
int n, fd;
char buf[5];
int count = 1;
if(fd = open("/var/log/Xorg.0.log", O_RDONLY)>0)
{
n= read(fd, buf, 5);
if (write(1,buf,n) != n)
printf("write error");

if (n < 0)
printf("read error");
}
else
printf("Unable to open file");

return(0);
}


Eitherway, you're saying this should work? because it isn't sending anything to the terminal.

wmcbrine
September 10th, 2009, 03:51 AM
Is there a reason you're using the low-level POSIX calls (open, read, write) instead of the more usual ANSI C buffered I/O (fopen, fread, fwrite)?

PmDematagoda
September 10th, 2009, 10:35 AM
Compiling both your old and new code with the -Wall option specified for GCC gives:-

ex.c: In function ‘main’:
ex.c:10: warning: suggest parentheses around assignment used as truth value
which means this line:-

if (fd = open ("/var/log/Xorg.0.log", O_RDONLY) > 0)
this problem is fixed with:-

if ( (fd = open("/var/log/Xorg.0.log", O_RDONLY)) > 0 )

PmDematagoda
September 10th, 2009, 10:44 AM
Here is a sample program that can get and output the complete contents of the file(mind you, it isn't perfect):-

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

int main(int argc, char **argv)
{
FILE *test_file;
char buf[4096];
if ( (test_file = fopen ("/var/log/Xorg.0.log", "r")) != NULL)
{
while (!feof (test_file))
{
fgets (buf, sizeof (buf), test_file);
puts (buf);
}
}
else
{
printf ("Error opening file: %s\n", strerror (errno));
exit (EXIT_FAILURE);
}

return 0;

}

fct
September 10th, 2009, 08:08 PM
argv[0] equals the path of the program. For example, for the command "ls filename" it would be "ls", not "filename".

You must use argv[1], but before check that it's been set by making sure argc == 2.

That way you don't need to set the file name in your source code.

fct
September 10th, 2009, 08:13 PM
So how do I get it to write out to the screen? what is the file descriptor for stdout? isn't it 1?


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
int n, fd;
char buf[5];
int count = 1;
if(fd = open("/var/log/Xorg.0.log", O_RDONLY)>0)
{
n= read(fd, buf, 5);
if (write(1,buf,n) != n)
printf("write error");

if (n < 0)
printf("read error");
}
else
printf("Unable to open file");

return(0);
}


Eitherway, you're saying this should work? because it isn't sending anything to the terminal.

To print to stdout, it is much easier to just use:

fprintf(stdout, "%.*s", n, buf);

or

printf("%.*s", n, buf);

dwhitney67
September 10th, 2009, 08:29 PM
To print to stdout, it is much easier to just use:

fprintf(stdout, ".*s", n, buf);

or

printf(".*s", n, buf);

Actually, it is easier to print the data one wants displayed using the correct syntax for the printf() function. ;)



printf("%s", buf);
fprintf(stdout, "%s", buf);


Or am I wrong, and has the C library changed on me since I last looked at it?

fct
September 10th, 2009, 08:38 PM
Actually, it is easier to print the data one wants displayed using the correct syntax for the printf() function. ;)



printf("%s", buf);
fprintf(stdout, "%s", buf);


Or am I wrong, and has the C library changed on me since I last looked at it?

1. It's correct syntax, and it's not new: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
2. In a char array with no null terminators, using printf("%s",...) on it the code might look beyond the array bounds until it finds a '\0' char in memory or is terminated because of a segmentation fault. That's why I specify the string length, which since it can vary with n is not hard-coded in the format string.

P.S.: Just thought that if the file you're reading has bytes set to 0 in the middle of it (not rare in binaries) printf will incorrectly interpret it as a string terminator, so it will not print the rest of the characters in the array. So it would only work if reading text files.

dwhitney67
September 10th, 2009, 10:12 PM
1. It's correct syntax, and it's not new: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
2. In a char array with no null terminators, using printf("%s",...) on it the code might look beyond the array bounds until it finds a '\0' char in memory or is terminated because of a segmentation fault. That's why I specify the string length, which since it can vary with n is not hard-coded in the format string.

P.S.: Just thought that if the file you're reading has bytes set to 0 in the middle of it (not rare in binaries) printf will incorrectly interpret it as a string terminator, so it will not print the rest of the characters in the array. So it would only work if reading text files.

I tested the printf() statement in your previous post under cygwin and it did not work as intended.

Under Ubuntu, I get the following warning:


gcc -Wall -pedantic -D_GNU_SOURCE -std=gnu99 printf.c
printf.c: In function ‘main’:
printf.c:8: warning: too many arguments for format


Here's the code I tested with:


#include <stdio.h>

int main()
{
const char* buf = "hello world";
const int n = 5;

printf(".*s", n, buf);
return 0;
}

Now, what in pray-tell am I missing here?

EDIT: Nevermind... as in your original post, I am missing the percent sign before the ".*s". The proper format should be:


printf("%.*s", n, buf);