Reading a file from stdin - c

It's been years since I programmed in C, and so I've been struggling a lot just to do a simply "get filename & path from stdin, read file, print file to stdout" task, which I know shouldn't be that hard but ya. Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void) {
int c;
FILE *file;
//scanf("%s", filename);
char *filename;
filename = (char *)malloc(200 * sizeof(char));
read(STDIN_FILENO, filename, 200);
printf("%s", filename);
file = fopen(filename, "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
} else {
printf("File not found.");
}
printf("\n");
return(0);
}
I my code continues to simply print out File not found., when I know for a fact my file path and everything is correct (not only because I literally drop it and past it into terminal from my folder with Mac OSX El Capitan - what a lovely feature, but also) because I had a different version of this program using scanf which found the file and read it perfectly fine, (as you can see I have it commented out on my code).
There is another program I'm writing that just uses this one, and I got rid of the scanf because I think it was negatively affecting other things in that program, so I want to be able to use read()
If anyone has any advice on how I can fix this or why this isn't working, that would be greatly appreciated as I've been at this for hours already and would very much like to move on to my actual program that I need to code!
THANKS A BUNCH

You must remove the '\n' new line character that is being read and stored into the filename buffer.
One of the many was to do it is include string.h and after reading the filename
char *newline = strchr(filename, '\n');
if (newline != NULL)
*newline = '\0';
Also, use fgets() instead of read() because that way the program is more portable. And more importantly, read() will not add the null terminator which is very important in order to use the buffer as a string — to pass it to fopen() for example — correctly. If you want to use read try something like this
ssize_t length;
char filename[200];
length = read(STDIN_FILENO, filename, sizeof(filename) - 1);
if (length <= 0)
return -1; // No input or input error
if (filename[length] == '\n')
filename[--length] = '\0';
else
filename[length] = '\0';
But otherwise, try this which is simpler
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *file;
char filename[200];
char *newline;
if (fgets(filename, sizeof(filename), stdin) == NULL)
return -1; // Input error / EOF
newline = strchr(filename, '\n');
if (newline) // ? is a newline present?
*newline = '\0';
printf("**%s**\n", filename); // ** will help checking for
// the presence of white spaces.
file = fopen(filename, "r");
if (file) {
int chr;
while ((chr = fgetc(file)) != EOF)
fputc(chr, stdout);
fclose(file);
} else {
printf("File not found.");
}
printf("\n");
return 0;
}

Related

How to take first row from this list of text?

I have a list of columns containing text but I just to fetch first upper row from this list. How to do that?
#include <stdio.h>
int main()
{
FILE *fr;
char c;
fr = fopen("prog.txt", "r");
while( c != EOF)
{
c = fgetc(fr); /* read from file*/
printf("%c",c); /* display on screen*/
}
fclose(fr);
return 0;
}
Your stop condition is EOF, everything will be read to the end of the file, what you need is to read till newline character is found, furthermore EOF (-1) should be compared with int type.
You'll need something like:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fr;
int c;
if(!(fr = fopen("prog.txt", "r"))){ //check file opening
perror("File error");
return EXIT_FAILURE;
}
while ((c = fgetc(fr)) != EOF && c != '\n')
{
printf("%c",c); /* display on screen*/
}
fclose(fr);
return EXIT_SUCCESS;
}
This is respecting your code reading the line char by char, you also have the library functions that allow you to read whole line, like fgets() for a portable piece of code, or getline() if you are not on Windows, alternatively download a portable version, and, of course you can make your own like this one or this one.
For whatever it's worth, here's an example that uses getline
#include <stdio.h>
int main()
{
FILE *fr;
char *line = NULL;
size_t len = 0;
ssize_t nread;
if (!(fr = fopen("prog.txt", "r"))) {
perror("Unable to open file");
return 1;
}
nread = getline(&line, &len, fr);
printf("line: %s, nread: %ld\n", line, nread);
fclose(fr);
return 0;
}
Some notes:
getline() can automatically allocate your read buffer, if you wish.
getline() returns the end of line delimiter. You can always strip it off, if you don't want it.
It's ALWAYS a good idea to check the status of I/O calls like "fopen()".
just replace EOF as '\n'(new line char). Than your code will read until reaching the new line. Here is what it looks like:
#include <stdio.h>
int main()
{
FILE *fr;
char c = ' ';
fr = fopen("prog.txt", "r");
while(c != EOF && c != '\n')
{
c = fgetc(fr); /* read from file*/
if(c != EOF){
printf("%c",c); /* display on screen*/
}
}
fclose(fr);
return 0;
}
I have not tested it yet but probably work. Please let me know if there is some problem with the code i will edit it.
Edit1:char c; in line 5 is initialized as ' ' for dealing with UB.
Edit2:adding condition (c != EOF) to while loop in line 7, for not giving reason to infinite loop.
Edit3:adding if statement to line 10 for not printing EOF which can be reason for odd results.

How to delete blank lines from a txt file with c, in linux - whitout Bash

I tried creating a .c program that when it is run it takes a file and it prints only the lines on which there is something (a space, a letter, a number....etc) not the blank lines.
I need to run this on a virtual machine using ubuntu(it's running the newest version of ubuntu). So far I have only managed to print it's contents but not on lines like they are in the file.
The code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *name = argv[1];
FILE *f = fopen(name, "r");
char x;
while(fscanf(f, "%c" , &x) > 0)
{
printf("%c", x);
if(x == '\n')
{
printf("\n");
}
}
}
file contents:
as
d
3
results:
asd3
desired result:
as
d
3
First, you have no error checking. That makes your program difficult to use.
Second, you output every character unconditionally and then output newlines an extra time. What you want to do is output every character once, unless it's a newline right after a newline (as that would create an empty line) in which case you don't want to output it.
Here's the code fixed up:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "An argument is required\n");
return -1;
}
char *name = argv[1];
FILE *f = fopen(name, "r");
if (f == NULL)
{
fprintf (stderr, "Unable to open file for reading\n");
return -1;
}
char x, px = '\n';
while(fscanf(f, "%c" , &x) > 0)
{
// don't output a newline after a newline
if ((x != '\n') || (px != '\n'))
printf("%c", x);
// keep track of what character was before the next one
px = x;
}
}
It really would be much easier to just read each line in and then output the line if it's non-empty.
You can use fgets() function which gets the entire line including the new line character (\n), After you read the line, you can skip printing the line if the first character (line[0]) is newline character.
Here is the code segment that does it, You need to error checking for argc and file existence as done by #David Schwartz
char line[200];
while (fgets(line, 100, fp))
{
if (line[0] != '\n')
printf(line);
}
This should work.

Opening Files in C

Full Edit:
I am getting frustrated, I don't know what am I doing wrong in here
I still have so many stuff to do in the code but I can't even open a file to continue my work.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void main()
{
char letter;
FILE *fp;
fp=fopen("‪‪‪C:\\Users\\LENOVO\\Desktop\\data.txt","r");
if(fp==NULL)
{
printf("error");
getch();
exit(1);
}
while(fscanf(fp,"%d",&letter)!=EOF)
putchar(letter);
getch();
fclose(fp);
}‪
Picture of the path: http://imgur.com/a/YwFYy
Still prints error
Ok, firstly let's take a look at your file path. There are two ways to acces a file from your local storage:
relative addresses if the file has the same root folder as your application
absolute addresses if the file is in a determined place on your machine's storage
I see that you are trying to use an absolute address to read from your file. Your path is correct but you have to take care about string formatting in C because the \ character could be interpreted as something else.
I would suggest to use this instead ( double back-slash )
input=fopen("‪C:\\Users\\LENOVO\\Desktop\\data.txt","r");
This will prevent string formatting interpretations.
Secondly, EOF is just a predefined macro constant and i think it is equal to -1 so your while(! (-1) ) code is not a good ideea for reading until the end of the file.
In order to read from a file until you reach the its end i would consider this property of fscanf() :
fscanf() returns EOF when it reaches the end of the file.
while(fscanf(input,"%ch",&letter) != EOF) {
putchar(letter);
}
This way of reading from a file should do the job.
To read everything from a text file and store its contents into a buffer:
First, you should count how many characters there are in the text file:
size_t get_file_len(FILE *fp)
{
size_t num = 0;
while (fgetc(fp) != EOF)
num++;
return (fseek(fp, 0, SEEK_SET) == 0 ? num : 0);
}
Then allocate memory for a buffer large enough and read all the characters:
char *load_text(const char *path)
{
char *buf = NULL;
FILE *fp = NULL;
size_t num = 0;
size_t i = 0;
int c = 0;
/* open the file in text mode */
fp = fopen(path, "r");
if (!fp)
return NULL;
/* if the file was empty or if an error occurred, return error */
if ((num = get_file_len(fp)) == 0) {
fclose(fp);
return NULL;
}
buf = malloc(num + 1);
if (!buf) {
fclose(fp);
return NULL;
}
while ((c = fgetc(fp)) != EOF)
buf[i++] = (char)c;
/* ensure that the string is null-terminated */
buf[i] = '\0';
fclose(fp);
return buf;
}
Also, in C, all escape sequences begin with a '\' (backslash), so if you wanted to write a backslash in a string or a char you should write it as a '\\' (double backslash):
input=fopen("‪C:\\Users\\LENOVO\\Desktop\\data.txt","r");
pretty simple here :
while(!feof(input)){
fscanf(input,"%c",&letter);
putchar(letter);
}
and remember to close file using fclose(input);

Why "scanf" works but fgets doesn't works in C?

Look here, those two programms should be equivalent in my opinion. But obviously they aren't, as the first programm works and the second doesn't. Can someone explain to me, why fgets() doesn't do the job?
// FIRST PROGRAM : WORKS FINE
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char fileName[67];
scanf("%s", fileName);
printf("%s", fileName);
stream = fopen(fileName, "r");
char ch;
if(stream){
ch = fgetc(stream);
while(!feof(stream)){
putchar(ch);
ch = fgetc(stream);
}
fclose(stream);
}
}
// SECOND PROGRAM: DOES NOT WORK
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char fileName[67];
fgets(fileName, 67, stdin);
printf("%s", fileName);
stream = fopen(fileName, "r");
char ch;
if(stream){
ch = fgetc(stream);
while(!feof(stream)){
putchar(ch);
ch = fgetc(stream);
}
fclose(stream);
}
}
I enter "test.txt" into the console both times and press enter then. Of course test.txt exists in the right directory
The reason is that fgets() retains the newline entered. You can verify it is there by altering your print statement to
printf("[%s]", filename);
when the ] will appear on the next line. You can remove the trailing newline like this
#include <string.h>
...
filename [ strcspn(filename, "\r\n") ] = 0;
The main problem you experienced is correctly solved by Weather Vane, but I want to point another problem with your code: the loops for reading and writing the contents of the file are incorrect. Testing the end of file with feof(stream) leads to incorrect behaviour most of the time. In your case, a read error from stream will cause your program to loop endlessly, writing 0xFF bytes to stdout.
There is a much simpler and idiomatic way to implement this loop:
if (stream) {
int ch;
while ((ch = fgetc(stream)) != EOF) {
putchar(ch);
}
fclose(stream);
}
As you can see, it is simpler and correctly tests for EOF at the right time, when input fails. It stores the return value of fgetc() into an int variable capable of holding all possible return values from fgetc(). Using an int is necessary because comparing a char value to EOF either always fails if the char type is unsigned or potentially gives false positives if char is signed and has value '\377'.

Data entry into array of character pointers in C

this is my first question asked on here so if I'm not following the formatting rules here please forgive me. I am writing a program in C which requires me to read a few lines from a file. I am attempting to put each line into a cstring. I have declared a 2D character array called buf which is to hold each of the 5 lines from the file. The relevant code is shown below
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h> /* UNIX domain header */
void FillBuffersForSender();
char buf[5][2000]; //Buffer for 5 frames of output
int main()
{
FillBuffersForSender();
return 0;
}
void FillBuffersForSender(){
FILE *fp;
int line = 0;
char* temp = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("frames.txt", "r");
printf("At the beginning of Fill Buffers loop.\n");
//while ((read = getline(&temp, &len, fp)) != -1){
while(line < 5){
//fprintf(stderr, "Read in: %s\n", temp);
fgets(temp, 2000, fp);
strcpy(buf[line], temp);
line++;
fprintf(stderr, "Line contains: %s.\n", temp);
temp = NULL;
}
while(line != 0){
fprintf(stderr, "Line contains: %s.\n", buf[line]);
line--;
}
}
The line
strcpy(buf[line], temp);
is causing a segmentation fault. I have tried this numerous ways, and cannot seem to get it to work. I am not used to C, but have been tasked with writing a bidirectional sliding window protocol in it. I keep having problems with super basic issues like this! If this were in C++, I'd be done already. Any help anyone could provide would be incredible. Thank you.
temp needs to point to an allocated buffer that fgets can write into.
In C programming, error checking is an important part of every program (in fact sometimes it seems like there's more error handling code than functional code). The code should check the return value from every function to make sure that it worked, e.g. if fopen returns NULL then it wasn't able to open the file, likewise if fgets returns NULL it wasn't able to read a line.
Also, the code needs to clean up after itself. For example, there is no destructor that closes a file when the file pointer goes out of scope, so the code needs to call fclose explicitly to close the file when it's finished with the file.
Finally, note that many of the C library functions have quirks that need to be understood, and properly handled. You can learn about these quirks by reading the man pages for the functions. For example, the fgets function will leave the newline character \n at the end of each line that it reads. But the last line of a file may not have a newline character. So when using fgets, it's good practice to strip the newline.
With all that in mind, the code should look like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 5
#define MAXLENGTH 2000
static char buffer[MAXLINE][MAXLENGTH];
void FillBufferForSender(void)
{
char *filename = "frames.txt";
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL)
{
printf("file '%s' does not exist\n", filename);
exit(1);
}
for (int i = 0; i < MAXLINE; i++)
{
// read a line
if (fgets( buffer[i], MAXLENGTH, fp ) == NULL)
{
printf("file does not have %d lines\n", MAXLINE);
exit(1);
}
// strip the newline, if any
size_t newline = strcspn(buffer[i], "\n");
buffer[i][newline] = '\0';
}
fclose(fp);
}
int main(void)
{
FillBufferForSender();
for (int i = 0; i < MAXLINE; i++)
printf("%s\n", buffer[i]);
}
Note: for an explanation of how strcspn is used to strip the newline, see this answer.
When it comes to C you have to think of the memory. Where is the memory for a point with NULL assigned to it? How can we copy something to somewhere that we have no space for?

Resources