Reading file, line by line, character by character in C - c

I have a problem with reading a file in C.
I want to read a file line by line.
Each line contains 25 characters and each character has a special value that I have to use in other functions. My code:
int read_file(const char* filename){
FILE* file = fopen(filename, "r");
char line[25];
int i;
int counter = 0;
while (fgets(line, sizeof(line), file))
{
if (counter == 0)
{
counter++;
}
else
{
for(i = 0; i < 25 ; i++){
printf("%s",line[i]);
}
}
}
fclose(file);
return 0;
}
I have to do something else then print it, but when I try this code, it gives errors, so doing something else would do the same I guess.
So my code needs to read the file line by line and then I need to be able to read it character by character.

An array of 25 elements isn't enough to store lines of 25 characters: +1 for newline and +1 for terminating null character.
You should check if the opening of the file is successful
%c have to be used to print one character via printf.
fixed code:
#include <stdio.h>
int read_file(const char* filename){
FILE* file = fopen(filename, "r");
char line[27]; /* an array of 25 elements isn't enough to store lines of 25 characters: +1 for newline and +1 for terminating null character */
int i;
int counter = 0;
if (file == NULL) return 1; /* check if the file is successfully opened */
while (fgets(line, sizeof(line), file))
{
if (counter == 0)
{
counter++;
}
else
{
for(i = 0; i < 25 ; i++){
printf("%c",line[i]); /* use %c instead of %s to print one character */
}
}
}
fclose(file);
return 0;
}

printf("%s",line[i]); // %s expects char * and line[i] is a char
This should be -
printf("%c",line[i]); // to print character by charcter
To store 25 characters declare line as -
char line[25+1]; // +1 for null character
Note - As you ask in comment to %s can be used as -
printf("%s",line); // no loop required

Related

In C, how can I produce an error if the input string is too big?

I want to read a list of words from a file, which has one word per line.
The words should have up to 4 characters each. How can I produce an error if one of the lines is longer than that?
I tried reading the words using fgets
char buf[5];
fgets(buf, 5, stdin);
and with scanf
char buf[5];
scanf("%4s", &buf);
but in both cases it splits long lines into smaller lines. For example qwerasdf is read as two words, qwer and asdf. Is there a way to detect that it tried to read a long line with more than 4 characters and give an error instead?
The only alternative I can think of is reading the input character-by-character and taking care of everything by myself. But is there a simpler solution using functions from the standard library?
You could check for the length of the read string and since fgets also reads the newline character, you could explicitly check for '\n' as the last input character.
char buf[6];
while (fgets(buf, sizeof(buf), stdin)) {
if (strlen(buf) > 5
|| (strlen(buf) == 5 && buf[strlen(buf) - 1] != '\n')) {
fprintf(stderr, "line too long\n");
exit(EXIT_FAILURE);
}
}
The buffer must consist of at least six characters: 4 input characters + 1 newline character + the string terminating NUL byte.
You are making an excellent choice reading with fgets(), the only rule-of-thumb you are breaking is don't skimp on buffer size. But, even if you do, you can handle things properly with fgets().
When you read a line from a file, fgets() (or POSIX getline()) read and include the '\n' as part of the buffer they fill (if there is room). If you are expecting up to 4-characters, then a buffer size of 5 is too-short-by-one to accommodate all your characters, the nul-terminating character, and the '\n'. Your circumstance attempting to read a 4-character line ("cats") with a 5-character buffer with fgets() would result in buf holding:
+---+---+---+---+---+
| c | a | t | s | \0| --> '\n' remains unread
+---+---+---+---+---+
You can gracefully handle that as well (but better not to skimp on buffer size) To gracefully handle the issue you need to check:
if '\n' is the last char in the buffer, complete line read, trim '\n' by overwriting with nul-terminating character;
otherwise, read next char;
if next char is '\n', then OK, you read all chars and there wasn't room for the '\n' which you just read and checked -- continue reading the next line;
else if next char is EOF, then you read all characters in the last line in a file with a non-POSIX end-of-file (no '\n' after the final line of data), break read loop you found EOF;
else additional character remain unread in the line, read and discard characters until the next '\n' or EOF is found
Putting that logic together, you could do:
#include <stdio.h>
#include <string.h>
int main (void) {
char buf[5];
while (fgets (buf, 5, stdin)) { /* read each line */
if (strchr (buf, '\n')) /* if '\n' found - line read */
buf[strcspn (buf, "\n")] = 0; /* nul-termiante at '\n' */
else { /* otherwise */
int c = getchar(); /* read next chars */
if (c == '\n') /* if '\n', OK read next line */
continue;
else if (c == EOF) /* if EOF, OK, non-POSIX eof */
break;
fputs ("error: line too long - discarding remainder.\n", stderr);
for (; c != '\n' && c != EOF; c = getchar()) {}
}
}
}
Look things over and let me know if you have further questions.
Here I made this function to read the file
char by char and returns only one line per call
so now you can read your file line by line, the
type Line has an array of chars value where we store
the line and an int hasNextLine 1 or 0 (bool)
that tell you if the file has another line or no,
this is handy when you loop over the file line by line.
#include <stdlib.h>
#include <stdio.h>
typedef struct {
char *value;
int hasNextLine;
} Line;
Line * getLine(FILE *file) {
Line *line = (Line *)malloc(sizeof(Line));
if(line == NULL) {
return NULL;
}
line->value = NULL;
line->hasNextLine = 1;
int n = 0, c;
while(1) {
c = getc(file);
char *tmpStr = (char *)realloc(line->value, n + 2);
if(tmpStr == NULL) {
line->hasNextLine = -1;
return line;
}
line->value = tmpStr;
if(c == EOF) {
line->hasNextLine = 0;
line->value[n] = '\0';
return line;
}
if(c == '\n') {
line->value[n] = '\0';
return line;
}
line->value[n] = c;
n++;
}
return line;
}
Usage:
// example reading one line
int main() {
FILE *f = fopen("your_file.txt", "r");
if(f == NULL) {
printf("File not found!");
return 1;
}
Line *l = getLine(f);
if(l != NULL) {
printf("%s\n", l->hasNextLine != -1 ? l->value :
"Error: while getting the line");
free(l->value);
free(l);
}
fclose(f);
return 0;
}
// example reading the whole file
int main() {
FILE *f = fopen("your_file.txt", "r");
if(f == NULL) {
printf("File not found!");
return 1;
}
Line *l;
int hasNextLine;
while(1) {
l = getLine(f);
if(l != NULL) {
printf("%s\n", l->hasNextLine != -1 ? l->value :
"Error: while getting the line");
free(l->value);
hasNextLine = l->hasNextLine;
free(l);
}
if(hasNextLine <= 0) {
break;
}
}
fclose(f);
return 0;
}
you can make a custom function for user input
char * sgetLine(char *msg) {
printf("%s", msg);
Line *l = getLine(stdin);
char *strLine = NULL;
if(l == NULL) {
return NULL;
}else {
if(l->hasNextLine == -1) {
free(l->value);
free(l);
return NULL;
}
strLine = l->value;
free(l);
return strLine;
}
}
so now you can use one function call to print
the question and to get the answer (char array)
int main() {
char *l = sgetLine("What is your name? ");
if(l != NULL) {
printf("%s\n", l);
}
free(l);
return 0;
}

Inconsistent reading of string from pipe

I read some data from a file, and send it through a pipe. When I read the data from the pipe, sometimes there's extra characters inside. The extra characters are also inconsistent, but normally is an extra "R" at the end.
The data I read from the file is correct, as it is always as it should be. It's only after reading it from the pipe that I encounter problems.
Could you help me find the error? I've been staring at this for ages and I can't find it.
This is the part of my code that is giving me trouble.
Thanks for your help.
int main (int argc, char **argv) {
int nClients;
int file_name_HTML[2];
create_pipes(file_name_HTML, server_access_request);
init_free_pipes();
nClients = getHTMLFilesIntoPipe(file_name_HTML);
int clients[nClients];
for(int i=0; i < nClients; i++)
{
if((clients[i] = fork()) == 0)
{
clientFunction(file_name_HTML, server_access_request);
}
}
.....
}
int getHTMLFilesIntoPipe(int *file_name_HTML)
{
int i, n = 0;
char (*lines)[MAXCHAR] = NULL;
FILE *fp;
fp = fopen("./data/listado_html.txt", "r");
if (!fp) { /* valdiate file open for reading */
err_exit("error: file open failed.\n");
}
if (!(lines = malloc (MAXLINES * sizeof *lines))) {
err_exit("error: virtual memory exhausted 'lines'.\n");
}
while (n < MAXLINES && fgets (lines[n], MAXCHAR, fp)) /* read each line */
{
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
if (*p != '\n') /* check line read */
{
int c;
while ((c = fgetc (fp)) != '\n' && c != EOF) {} /* discard remainder of line with getchar */
}
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < n; i++)
{
write(file_name_HTML[WRITE], lines[i], strlen(lines[i]));
}
free(lines);
return n;
}
void clientFunction(int *file_name_HTML, int *server_access_request)
{
char fileName[MAXCHAR];
close(file_name_HTML[WRITE]);
//Read HTML file name
read(file_name_HTML[READ], fileName, MAXCHAR - 1);
printf("%s\n", fileName);
.......
}
Expected output:
abcd1.html
abcd2.html
abcd3.html
abcd4.html
abcd5.html
Current output:
abcd1.htmlR
abcd2.htmlR
abcd3.htmlR
abcd4.htmlR
abcd5.htmlR
It is because your string is not null(\0) terminated.
As you write to the pipe excluding null(\0) terminator.
write(file_name_HTML[WRITE], lines[i], strlen(lines[i])+1);
^--- +1 to include null character.
strlen returns the length excluding null terminator.

C: fgets return an extra blank line at beginning

I am trying to read a file and reverse each line of it and display it to standard output in C.
my file is:
$ cat f1
this is line 1
this is line 2
this is line 3
My code is:
#include <stdio.h>
#include <string.h>
void reverse_string(char *s) {
int l = strlen(s);
int i;
char sr[l];
int j = 0;
for (i = l - 1; i >= 0; i--) {
sr[j] = s[i];
j++;
}
printf("%s", sr);
}
int main(int argc, char *argv[]) {
FILE *fp;
int i;
char filename[128];
char line[100];
for (i = 1; i < argc; i++) {
strcpy(filename, argv[i]);
}
fp = fopen(filename, "r");
while (fgets(line, 128, fp) != NULL) {
if (strlen(line) != 0) {
reverse_string(line);
}
}
printf("\n");
}
Output is:
$ ./mycode f1
(blank line here)
1 enil si siht
2 enil si siht
3 enil si siht
I am confused, why is there a extra blank line being output by my while loop even though there is no blank line in the file.
fgets includes a '/n' before nul char.
So when you reverse a string, the first thing you do is print it.
My ugly fix is:
replace the fist printf with
printf("%s\n", sr+1);
remove the second one.
And remember, when all fails, read the manual.:
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s.
Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer.
A terminating null byte ('\0') is stored after the last character in the buffer.
I am also trying to read from the file. My file contains the user's name and after reading username I need to add a constant character to each user. But when I am reading the file, I am getting unwanted empty lines in output and constant character is showing at empty line not together with the user name.
int main()
{
char buffer[20] ;
char i, j;
const char *a="love";
FILE *fp;
if ((fp = fopen("user.txt","r")) == NULL)
{
perror ("Error opening file");
}
while ( !feof(fp))
{
// read in the line and make sure it was successful
if (fgets(buffer,20,fp) != NULL)
{
cout << buffer << endl;
for(i = 0; buffer[i] != '\0'; ++i);
for(j = 0; a[j] != '\0'; ++j, ++i)
{
buffer[i] = a[j];
}
buffer[i] = '\0' ;
//cout << buffer << endl ;
}
}
}
I am getting output like this
asharma5
love
as23w
love
qwssdd
love
My desired output is adding love to each user name.
asharma5love
as23wlove
qwssddlove

Adding chars to char array from csv.

I am trying to take a csv file and assign the strings from it to a csv. I've tried a couple of things with very little luck. This is what I have so far:
int main(int argc, char* argv []) {
FILE *file = fopen( argv[1], "r" );
int x;
char strings[50];
while ((x = fgetc(file)) != EOF) {
printf( "%c", x);
}
fclose(file);
return 0;
}
I've created the strings char array, but I'm unsure how to assign the contents of my csv into it. Any ideas?
Thanks in advance.
You can use fgets to directly read into array strings-
char strings[255]; //give size accordingly
while(fgets(strings,sizeof strings,file)!=NULL) { //iteratre until fgets return NULL
printf("%s", strings); //print string that is read from file
}
Note-
1.You have not checked value of argc as well as return of fopen . You should probably check them .
You can use your characterwise reading approach. Fill your temporary buffer as you go, but take care not to overflow it. When you encounter a separator – a comma for columns, a newline for rows – process the current buffer.
Reset the buffer, adjust the current row and column and repeat until you find the end of the file. When you want to store the content of a cell, be sure to make a copy, because the scratch buffer will be overwritten.
Here's a simple example that just prints the data:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
FILE *file = fopen("example.csv", "r");
// check for errors
char buf[50];
int nbuf = 0;
int row = 0;
int col = 0;
for (;;) {
int c = fgetc(file);
if (c == EOF) break;
if (c == '\n' || c == ',') {
buf[nbuf] = '\0';
printf("[%d][%d] '%s'\n", row, col, buf);
nbuf = 0;
if (c == ',') {
col++;
} else {
col = 0;
row++;
}
} else {
if (nbuf + 1 < sizeof(buf)) buf[nbuf++] = c;
}
}
fclose(file);
return 0;
}

File reading in C. Complications with fread function

I'm reading an input file and I am having complications regarding reading each line in it. My input file has two types of records. One has 52 characters while the other has 926. I don't know what to do with my fread function so that it can handle both records. Can anyone help me out? thanks
#define LINESZ 927 /* one extra byte for new line */
int num; /* integer for line number */
char buffer[LINESZ]; /* buffer for file read line */
int main()
{
FILE *ifp, *ofp;
ifp = fopen("dd:INPUTF", "r");
ofp = fopen("dd:OUTPUTF", "w");
while (!feof(ifp)) {
if (num = (fread(buffer, sizeof(char), LINESZ, ifp))) {
if (buffer[22] == 'O') {
printf("ravroot, %c\n", buffer[22]);
printf("%s*\n", buffer);
}
else if (buffer[22] == 'A') {
printf("ravrate, %c\n", buffer[22]);
printf("%s*\n", buffer);
}
}
}
fclose(ifp);
fclose(ofp);
return(0);
}
When reading lines from a file, you should use the fgets function. Note however, that fgets will write the newline character to your buffer, so you need to strip the newline out. The resulting code looks like this
#define LINESZ 1024 /* lots of extra bytes, memory is cheap */
char buffer[LINESZ]; /* buffer for file read line */
int main( void )
{
int length;
FILE *ifp, *ofp;
ifp = fopen("dd:INPUTF", "r");
ofp = fopen("dd:OUTPUTF","w");
while( fgets( buffer, LINESZ, ifp ) != NULL )
{
// remove the newline character, if any
length = strlen( buffer );
if ( length > 0 && buffer[length-1] == '\n' )
buffer[--length] = '\0';
if ( length > 22 )
{
if(buffer[22] == 'O')
{
printf("ravroot, %c\n", buffer[22]);
printf("%s*\n", buffer);
}
else if(buffer[22] == 'A')
{
printf("ravrate, %c\n", buffer[22]);
printf("%s*\n", buffer);
}
}
}
fclose(ifp);
fclose(ofp);
return(0);
}
If every record is in seperate line thne use the fgets function which will stop when the newline is encountered , eg:
while(fgets(buf,LINESZ,ifp) != NULL)
{
//you can put your code here
}

Resources