Reading line by line C - c

I have a txt file with some file names and their size.
This is how I wrote the txt file:
banana //file name
3 //the size of file banana
programs
12
music
524
I have to find a keyboard entered file name and display it's size.
This is my code:
FILE *text;
text=fopen("text.txt","r");
printf("Scan the number of letters of your file name");
int n;
scanf("%d",&n);
char s[++n];
printf("Scan the file name you are looking for: ");
int i;
for(i=0;i<=n;i++)
{
scanf("%c",&s[i]);
}
int l=0;
char c[n];
char g;
while(!feof(text))
{
if(l%2==1) {fgetc(text); fgetc(text); l++;}
if(l%2==0)
{
fgets(c,n,text);
fgetc(text);
for(i=0;i<n;i++)
{
printf("%c",c[i]);
}
l++;
}
}
Obviously, it's not correct. Can you help me? I'm a little bit confuse.

Ugh! Please learn more about basic input. Your program has various flaws:
fgetc reads single characters. This can be useful at times, but obviously you want to read whole lines. fgets does this. You use it once, but it is not advisable to mix these. Decide up front which input paradigm you want to use: char-wise (fgetc), line-wise (fgets) or token-wise (fscanf).
Please don't make the user enter the number of characters in the filename. Quick, how many characters are there in MySpiffyDocument.txt? That's work that the computer should do.
Don't use feof to control yopur input. All input functions have special return values toat indicate that either the end of the file was read or that an error occurred. For fgets, this return value is NULL, for fgetc, this return value is the special constant EOF. The functions feof and ferror are useful after you have encountered the special return values for a post mortem analysis of the two end conditions.
Your inner loop, which is responsible for the core program logic, doesn't make sense at all. For example, for an odd l, increment l and then test for an even l – which will be true, because you have just incrremented an odd l. Use else in such cases. And don't place things that happen anyway in conditional blocks: Increment l once after the if/else blocks.
Here's an example implementation:
#include <stdlib.h>
#include <stdio.h>
int process(const char *filename)
{
char line[80];
char name[80];
int size;
int count = 0;
FILE *f = fopen(filename, "r");
if (f == NULL) return -1;
while (fgets(line, sizeof(line), f)) {
if (count % 2 == 0) {
if (sscanf(line, "%s", name) < 1) continue;
} else {
if (sscanf(line, "%d", &size) < 1) continue;
printf("%12d %s\n", size, name);
}
count++;
}
fclose(f);
return 0;
}
int main()
{
char line[80];
char name[80];
puts("Please enter filename:");
while (fgets(line, sizeof(line), stdin)) {
if (sscanf(line, "%s", name) == 1) {
process(name);
break;
}
}
return 0;
}
Things to note:
The program uses 80 characters a max. buffer size; that means your lines can be up to 78 characters long – line content plus new-line '\n' plus null terminator '\0'. That should be okay for many cases, but eventually the line may overflow. (So your file-name letter count has some merit, but the real solution here is to allocate memory dynamically. I won't open that can of worms now.)
The code uses a double strategy: Read lines first, then scan into these lines with sscanf, so that only the first word on each line is read.
Empty lines are skipped. Even lines that don't hold a valid number are skipped, too. This is sloppy error handling and may trip the odd/even count.
Reading stuff interactively from the keyboard isn't very easy in C. The awkward fgets/sscanf construct in main tries to handle the case when the user enters an empty line or evokes an end-of-file signal via Ctrl-D/Z. A better and easier way is to provide arguments to the command line via argc and argv.
I've moved the file reading into a separate function.

Related

How to create 2D array from text file and print to new file in c

Wondering if I could get some advice. Firstly, I am very new to programming, so I apologise for any silly mistakes. Please feel free to point them out and I will try to go research to improve.
I feel I am doing something fundamentally wrong with my array.
I am trying to read in from a file whose filename is specified by user input, store the information from the file in a 2D array, which I then plan to print into another file, again defined by user input.
I am currently printing out the array, to check that it has been stored, but I believe I am using the 2D array incorrectly, as when I try to fprintf into my file, it just does not work.
Any advice would be greatly appreciated.
Thank you. Code as follows:
#include <stdio.h>
#include <string.h>
int main()
{
char finame[100];
printf("Enter file you would like to open: ");
scanf("%s", finame);
FILE *in = fopen(finame, "r");
char foname[100];
printf("Enter the filename you would like the output included in: ");
scanf("%s", foname);
FILE *out = fopen(foname, "w");
/*Char array to store string */
char str[50][20];
int i =0;
/*Loop for reading the file till end*/
while((fgets(str[i],sizeof(str[i]), in)) != NULL) {
fputs(str[i++],stdout);
//getchar();
}
return 0;
}
Avoid mixing fgets(), scanf() calls. scanf() leaves a newline character in the input buffer which is later consumed by fgets() (doesn't
matter in this case since input comes from a file not from stdin but a good practice overall).
There is also no protection for overflow, if you want to stick to scanf() add a width specifier and check the result to see if it succeeded.
if (scanf("%99s", finame) != 1) /* save one byte for \0 */
{
/* handle error case */
}
Check that you don't exceed the size of your array while writing to it.
Added 2 define directives that could clean your code up.
#define MAX_LINES 50
#define MAX_CHAR 20
char str[MAX_LINES][MAX_CHAR];
int i = 0;
while (i < MAX_LINES && (fgets(str[i], MAX_CHAR, in)) != NULL) /* always check if running out bounds */
{
fputs(str[i++], stdout);
}
The problem with the above code is that, if the file gets too big, you will end up missing data, what you could do is have a dynamic array and use a malloc / realloc approach to expand the array or a linked list.

sum of unlimited integers by taking Input from a file in C

Here my question is calculating the sum of infinite no.of integers where the input is taken from a file.The file contains infinite no.of integers in a line delimited by space.And also I need to display invalid input if those input of integer contain any other characters or symbols.I had tried this code and output well
Here is my code....
void main()
{
int i=1,j,a[100000],total=0,r=0;
char discard,buffer[1024];
FILE *fp;
char filename[100];
scanf("%s",filename);
fp=fopen(filename,"r");
do
{
fscanf(fp,"%1024s%c",buffer,&discard);
r+=sscanf(buffer,"%d",&a[i]);
total+=a[i++];
} while(discard!='\n');
if(r==i-1)
{
printf("\n%d",total);
}
else
printf("\n Invalid Input");
}
The code is executing well.But the problem here is the code exceeding my time constraint.Please help me so that i could get a better code
You can read the file in chunks, speeding up the reading into integers. For hints, look at the fread() example in this link (search for e.g. 'sentinel' in the linked page): How do I process a text file in C by chunks of lines? Also, look at the comments to that answer, e.g. good idea to do malloc instead of stack allocation, maybe use binary mode, heed comment about EOF etc.
Get file size
Allocate dynamic memory buffer via malloc
Read all file into allocated memory buffer.
Make other actions from memory buffer.
I don't know if this will improve performance a lot, but the code is more readable and I also removed the use of stack buffers
void main()
{
int value = 0, total = 0, r = 0;
char discard;
FILE *fp;
char filename[100];
scanf("%s",filename);
fp = fopen(filename,"r");
do
{
r = fscanf(fp, "%d%c", &value, &discard);
if (r != 2 || (discard != ' ' && discard != '\n'))
{
printf("\n Invalid Input");
return;
}
total += value;
} while(discard != '\n');
printf("\n%d", total);
}
(Note that it's untested, but I'm confident)

How to save every line in file (IN C) in a variable? :)

I need to save every line of text file in c in a variable.
Here's my code
int main()
{
char firstname[100];
char lastname[100];
char string_0[256];
char string[256] = "Vanilla Twilight";
char string2[256];
FILE *file;
file = fopen("record.txt","r");
while(fgets(string_0,256,file) != NULL)
{
fgets(string2, 256, file);
printf("%s\n", string2);
if(strcmp(string, string2)==0)
printf("A match has been found");
}
fclose(file);
return 0;
}
Some lines are stored in the variable and printed on the cmd but some are skipped.
What should I do? When I tried sscanf(), all lines were complete but only the first word of each line is printed. I also tried ffscanf() but isn't working too. In fgets(), words per line are complete, but as I've said, some lines are skipped (even the first line).
I'm just a beginner in programming, so I really need help. :(
You're skipping over the check every odd number of lines, as you have two successive fgets() calls and only one strcmp(). Reduce your code to
while(fgets(string_0,256,file) != NULL)
{
if( ! strcmp(string_0, string2) )
printf("A match has been found\n");
}
FWIW, fgets() reads and stores the trailing newline, which can cause problem is string comparison, you need to take care of that, too.
As a note, you should always check the return value of fopen() for success before using the returned pointer.

How would I compare a string (entered by the user) to the first word of a line in a file?

I am really struggling to understand how character arrays work in C. This seems like something that should be really simple, but I do not know what function to use, or how to use it.
I want the user to enter a string, and I want to iterate through a text file, comparing this string to the first word of each line in the file.
By "word" here, I mean substring that consists of characters that aren't blanks.
Help is greatly appreciated!
Edit:
To be more clear, I want to take a single input and search for it in a database of the form of a text file. I know that if it is in the database, it will be the first word of a line, since that is how to database is formatted. I suppose I COULD iterate through every single word of the database, but this seems less efficient.
After finding the input in the database, I need to access the two words that follow it (on the same line) to achieve the program's ultimate goal (which is computational in nature)
Here is some code that will do what you are asking. I think it will help you understand how string functions work a little better. Note - I did not make many assumptions about how well conditioned the input and text file are, so there is a fair bit of code for removing whitespace from the input, and for checking that the match is truly "the first word", and not "the first part of the first word". So this code will not match the input "hello" to the line "helloworld 123 234" but it will match to "hello world 123 234". Note also that it is currently case sensitive.
#include <stdio.h>
#include <string.h>
int main(void) {
char buf[100]; // declare space for the input string
FILE *fp; // pointer to the text file
char fileBuf[256]; // space to keep a line from the file
int ii, ll;
printf("give a word to check:\n");
fgets(buf, 100, stdin); // fgets prevents you reading in a string longer than buffer
printf("you entered: %s\n", buf); // check we read correctly
// see (for debug) if there are any odd characters:
printf("In hex, that is ");
ll = strlen(buf);
for(ii = 0; ii < ll; ii++) printf("%2X ", buf[ii]);
printf("\n");
// probably see a carriage return - depends on OS. Get rid of it!
// note I could have used the result that ii is strlen(but) but
// that makes the code harder to understand
for(ii = strlen(buf) - 1; ii >=0; ii--) {
if (isspace(buf[ii])) buf[ii]='\0';
}
// open the file:
if((fp=fopen("myFile.txt", "r"))==NULL) {
printf("cannot open file!\n");
return 0;
}
while( fgets(fileBuf, 256, fp) ) { // read in one line at a time until eof
printf("line read: %s", fileBuf); // show we read it correctly
// find whitespace: we need to keep only the first word.
ii = 0;
while(!isspace(fileBuf[ii]) && ii < 255) ii++;
// now compare input string with first word from input file:
if (strlen(buf)==ii && strstr(fileBuf, buf) == fileBuf) {
printf("found a matching line: %s\n", fileBuf);
break;
}
}
// when you get here, fileBuf will contain the line you are interested in
// the second and third word of the line are what you are really after.
}
Your recent update states that the file is really a database, in which you are looking for a word. This is very important.
If you have enough memory to hold the whole database, you should do just that (read the whole database and arrange it for efficient searching), so you should probably not ask about searching in a file.
Good database designs involve data structures like trie and hash table. But for a start, you could use the most basic improvement of the database - holding the words in alphabetical order (use the somewhat tricky qsort function to achieve that).
struct Database
{
size_t count;
struct Entry // not sure about C syntax here; I usually code in C++; sorry
{
char *word;
char *explanation;
} *entries;
};
char *find_explanation_of_word(struct Database* db, char *word)
{
for (size_t i = 0; i < db->count; i++)
{
int result = strcmp(db->entries[i].word, word);
if (result == 0)
return db->entries[i].explanation;
else if (result > 0)
break; // if the database is sorted, this means word is not found
}
return NULL; // not found
}
If your database is too big to hold in memory, you should use a trie that holds just the beginnings of the words in the database; for each beginning of a word, have a file offset at which to start scanning the file.
char* find_explanation_in_file(FILE *f, long offset, char *word)
{
fseek(f, offset, SEEK_SET);
char line[100]; // 100 should be greater than max line in file
while (line, sizeof(line), f)
{
char *word_in_file = strtok(line, " ");
char *explanation = strtok(NULL, "");
int result = strcmp(word_in_file, word);
if (result == 0)
return explanation;
else if (result > 0)
break;
}
return NULL; // not found
}
I think what you need is fseek().
1) Pre-process the database file as follows. Find out the positions of all the '\n' (carriage returns), and store them in array, say a, so that you know that ith line starts at a[i]th character from the beginning of the file.
2) fseek() is a library function in stdio.h, and works as given here. So, when you need to process an input string, just start from the start of the file, and check the first word, only at the stored positions in the array a. To do that:
fseek(inFile , a[i] , SEEK_SET);
and then
fscanf(inFile, "%s %s %s", yourFirstWordHere, secondWord, thirdWord);
for checking the ith line.
Or, more efficiently, you could use:
fseek ( inFile , a[i]-a[i-1] , SEEK_CURR )
Explanation: What fseek() does is, it sets the read/write position indicator associated with the file at the desired position. So, if you know at which point you need to read or write, you can just go there and read directly or write directly. This way, you won't need to read whole lines just to get first three words.

Reading from two columns into variables

I'm writing a C program that takes an input file and stores it. The input file has two columns, with an integer in the first and a string in the second, like so:
12 apple
17 frog
20 grass
I've tried using fgets to take an entire line as a string then break it apart using scanf but I'm getting lots of issues. I have searched quite a lot but haven't found anything that answers my question, but sorry if I missed something obvious.
This is the code that I've been trying:
while(fgets(line, sizeof(line), fp))
{
scanf(line, "%d\t%s", &key, value);
insert(key, value, newdict);
}
Let's have a quick go at doing with strtok since someone mentioned it. Let's imagine your file is called file.txt and has the following contents:
10 aaa
20 bbb
30 ccc
This is how we can parse it:
#include <stdio.h>
#include <string.h>
#define MAX_NUMBER_OF_LINES 10 // parse a maximum of 10 lines
#define MAX_LINE_SIZE 50 // parse a maximum of 50 chars per line
int main ()
{
FILE* fh = fopen("file.txt", "r"); // open the file
char temp[MAX_LINE_SIZE]; // some buffer storage for each line
// storage for MAX_NUMBER_OF_LINES integers
int d_out[MAX_NUMBER_OF_LINES];
// storage for MAX_NUMBER_OF_LINES strings each MAX_LINE_SIZE chars long
char s_out[MAX_NUMBER_OF_LINES][MAX_LINE_SIZE];
// i is a special variable that tells us if we're parsing a number or a string (0 for num, 1 for string)
// di and si are indices to keep track of which line we're currently handling
int i = 0, di = 0, si = 0;
while (fgets(temp, MAX_LINE_SIZE, fh) && di < MAX_NUMBER_OF_LINES) // read the input file and parse the string
{
temp[strlen(temp) -1] = '\0'; // get rid of the newline in the buffer
char* c = strtok(temp, " "); // set the delimiters
while(c != NULL)
{
if (i == 0) // i equal to 0 means we're parsing a number
{
i = 1; // next we'll parse a string, let's indicate that
sscanf(c, "%d", &d_out[di++]);
}
else // i must be 1 parsing a string
{
i = 0; // next we'll parse a number
sprintf(s_out[si++], "%s", c);
}
c = strtok(NULL, " ");
}
printf("%d %s\n", d_out[di -1], s_out[si - 1]); // print what we've extracted
}
fclose(fh);
return 0;
}
This will extract the contents from the file and store them in respective arrays, we then print them and get back our original contents:
$ ./a.out
10 aaa
20 bbb
30 ccc
Use:
fgets (name, 100, stdin);
100 is the max length of the buffer. You should adjust it as per your need.
Use:
scanf ("%[^\n]%*c", name);
The [] is the scanset character. [^\n] tells that while the input is not a newline ('\n') take input. Then with the %*c it reads the newline character from the input buffer (which is not read), and the * indicates that this read in input is discarded (assignment suppression), as you do not need it, and this newline in the buffer does not create any problem for next inputs that you might take.
The problem here seems to be that you are reading from the file twice. First with fgets and then with scanf. You will probably not get an errors from the compiler in your use of scanf, but should be getting warnings as you use line for the format string and the other arguments does not match the format. It would also be pretty obvious if you checked the return value from scanf, as it returns the number of successfully scanned items. Your call would most likely return zero (or minus one when you have hit end of file).
You should be using sscanf instead to parse the line you read with fgets.
See e.g. this reference for the different scanf variants.
Your problem can be solved by using sscanf (with the support of getline) like below:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
/* tokens bags */
char tok_str[255];
int tok_int;
fp = fopen("./file.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
/* Reads the line from the stream. */
while ((read = getline(&line, &len, fp)) != -1) {
/* Scans the character string pointed by line, according to given format. */
sscanf(line, "%d\t%s", &tok_int, tok_str);
printf("%d-%s\n", tok_int, tok_str);
}
if (line)
free(line);
exit(EXIT_SUCCESS);
}
Or, even simpler. You could use fscanf (with the support of feof) and replace the while loop shown above (along with some other redundant code cleanups) with the following one:
/* Tests the end-of-file indicator for the stream. */
while (!feof(fp)) {
/* Scans input from the file stream pointer. */
fscanf(fp,"%d\t%s\n",&tok_int, tok_str);
printf("%d-%s\n", tok_int, tok_str);
}
Assuming that your file contains following lines (where single line format is number[tab]string[newline]):
12 apple
17 frog
20 grass
the output will be:
12-apple
17-frog
20-grass

Resources