I'm trying to make a sort of a database program and ran into a few issues with reading integers from a text file in C.
I have the following code:
#include <stdio.h>
int main(){
int index;
FILE * fp;
if((fp = fopen("read_file.txt","r+")) == NULL){
perror("Cannot open file");
printf("\nCreating new file...");
if((fp = fopen("read_file.txt","w+")) == NULL){
perror("\nCannot create file.. Terminating..");
return -1;
}
}
fputs("INDEX = 3",fp);
fscanf(fp, "INDEX = %d",&index);
printf("index = %d\n",index);
fclose(fp);
return 0;
}
When i try to run the program it outputs "index = 16", i tried using fgets and sscanf but same thing happens. With strings however it decides to print out a bunch of characters that don't make sense.
What you see in undefined behavior because you write a string to the file and try to scan INDEX = %d which is not there in the file because of the file pointer is pointing after INDEX = 3
You need to rewind(fp) before scanning.
fputs("INDEX = 3",fp);
rewind(fp);
if( fscanf(fp, "INDEX = %d",&index) != 1)
printf("Scanning failes\n");
else
printf("INDEX = %d\n",index);
Related
I wrote this code where I generate random integers in a large quantity and store them in a txt file. it works if I input up to 49 integers
but after that it does not read any further from the file or the file don't accept any further I don't know please help me
this is the code
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fptr;
int num, n;
fptr = fopen("integers.txt", "w");
if (fptr != NULL)
{
printf("File created successfully!\n");
}
else
{
printf("Failed to create the file.\n");
return -1;
}
printf("Enter some integer numbers [Enter -1 to exit]: ");
scanf("%d", &n);
while (n != 0)
{
num = rand();
putw(num, fptr);
n--;
}
fclose(fptr);
fptr = fopen("integers.txt", "r");
printf("\nNumbers:\n");
int count = 0;
while ((num = getw(fptr)) != EOF)
{
printf("%d\n", num);
count++;
}
printf("\nNumber of elements in the file %d",count);
fclose(fptr);
return 0;
}
You have following problems:
As you're writing binary data, the file needs to be opened with "wb" and "rb" (b stands for binary). Othwerwise certain unwanted text substitutions will take place.
If one of your random numbers turns out to be -1, the read will stop prematurely because EOF has the value -1. Therefore you need to do the end of file check with the feof function instead of comparing the value read with EOF.
fptr = fopen("integers.txt", "wb"); // <<< open with binary mode "wb"
...
fptr = fopen("integers.txt", "rb"); // <<< open with binary mode "rb"
printf("\nNumbers:\n");
int count = 0;
while (1)
{
num = getw(fptr);
if (feof(fptr)) // end of file reached => stop the loop
break;
printf("%d\n", num);
count++;
}
BTW:
The documentation of getw concerning the return value is pretty misleading, especially the part "A return value of EOF indicates either an error or end of file" seems wrong to me. getw can read -1 values (0xffffffff) without problems.
I'm having trouble setting the file pointer to the very start of a file to write some stuff at first AFTER having already written some text in it.
I've tried rewind(), fseek(), opening the file in "r+" & "a+" modes, nothing seems to work.
Here's a small recreation of the program:
#include<stdio.h>
#include<stdlib.h>
void master_globalprint(int lim)
{
int i = 0;
FILE* maspass;
errno_t err;
err = fopen_s(&maspass, "Master_Password.txt", "r+");
if (err != 0)
{
printf("Error opening Master_Password.txt");
exit(0);
}
rewind(maspass);
printf("Pointing to %ld", ftell(maspass));
while (i < lim)
{
fprintf(maspass, "%d", i); //Writing the array infront of the encrypted code
i++;
}
fclose(maspass);
}
void master_create() //To Create a Master Password
{
int count = 0;
char pass;
FILE* maspass;
errno_t err;
err = fopen_s(&maspass, "Master_Password.txt", "a");
if (err != 0)
{
printf("Error creating Master_Password.txt");
exit(0);
}
printf(" Enter Master Password : ");
while ((pass = getchar()) != EOF && pass != '\n')
{
count++;
fprintf(maspass, "%c", pass); //The characters are then printed one by one
}
if (count == 0)
{
remove("Master_Password.txt");
printf("Master Password cannot be empty");
exit(0);
}
fprintf(maspass, "%c", (count + 33)); //To put the amount of letters into file, forwarded by 33 to reach a certain ASCII threshold and converted to char
fprintf(maspass, "\n");
fclose(maspass);
master_globalprint(count);
}
void main()
{
master_create();
}
The above functions work and print the correct values except the master_globalprint function starts printing exactly where the last function left off.
Is it because I've to use command line arguments to achieve the task? If so, can I set the command line arguments to be executed by default somehow so that if the code is distributed, the user won't have to bother?
EDIT : Added in a reproducible code sample. When I put "a" in line 31, it prints only the stuff I input and not the numbers in master_globalprint(). If I put "w", it ONLY prints the numbers in master_globalprint() and not the stuff I input.
Here the writing mode should be w+:
err = fopen_s(&maspass, "Master_Password.txt", "a" /* w+ */);
Here you should close the file and then remove it:
if (count == 0)
{
/*fclose_s(maspass);*/
remove("Master_Password.txt");
printf("Master Password cannot be empty");
exit(0);
}
Instead of doing this, you should keep the file descriptor open and pass it to master_globalprint:
fclose(maspass);
master_globalprint(count);
/* master_globalprint(count, maspass);
* fclose(maspass); */
Then keep reusing the open file descriptor.
I'm trying to get better at coding in general and C in particular, and am coding a small text adventure game. I read a string input by the user i.e LOOK room and compare it to a txt file with the list of commands for that particular section.
As I am reading from the text file I have a counter which keeps track of which line is being read, when the match is made I convert the line number to a character and concatenate it to "outside.txt" so that when the correct command is input it will read from the correct file i.e LOOK room would load text from 1outside.txt etc.
However, when inputting anything it just loops on "I dont understand" forever. Any explanation as to why or constructive comments on my code are appreciated, especially if I am misunderstanding how files and/or strings in c.
int mansionOutside(void)
{
int stop = 1;
char choice[25];
char word_match[25];
char text_line[73];
char line1[25];
char temp[2];
int counter;
FILE *fptr;
fptr = fopen("mansion_commands.txt", "r");
if (fptr == NULL)
{
printf("ERROR!");
}
else
{
while (stop == 1)
{
printf("\n");
fgets(choice, sizeof choice, stdin);
while (fgets (line1, 25, fptr)!= NULL)
{
if (strcmp(line1, choice) == 0)
{
printf("%s\n", line1);
stop = 0;
break;
}
else
{
counter++;
printf("%s + %s\n", line1, choice);
}
}
if (stop == 1)
{
printf("I dont understand\n");
counter = 1;
}
}
fclose(fptr);
counter = counter + '0';
temp[0] = counter;
temp[1] = '\0';
strncat(word_match, temp , 1);
strcat(word_match, ".txt");
fptr = fopen(word_match, "r");
if (fptr == NULL)
{
printf("ERROR!\n");
}
else
{
printf("Debugging : File opened Successfully\n");
while (fgets (text_line, 72, fptr) != NULL)
{
printf("%s", text_line);
//delay(2);
}
}
}
}
EDIT : Took in suggestions for improvements to avoid Buffer overflows such as using > fgets , but I think there is something I have missed. Now If I input anything contained in the file, it works fine. If however I input something wrong, then something correct on re-prompt, It skips the inner while loop all together and goes straight to "I don't understand".
The following is what happens when my input is LOOK room, and then LOOK mansion.
I'm trying to read two records form a file, where one is hexadecimal formated number. Well I'm newcomer to C, before when I been reading hexadecimal, generated by ftok(), I just used printf("%x", key) and it worked fine. Now when I try to read it from the file, it does not work that way.
So my code looks like this:
int countRecords(FILE *f_p) {
int tmp_key = 0;
int tmp_msgqid = 0;
int n = 0;
while (!feof(f_p)) {
if (fscanf(f_p, "%x %i", &tmp_key, &tmp_msgqid) != 2)
break;
n = n + 1;
}
return n;
}
Later on i read this value in the code like:
printf("Records: %i \n", countRecords(f_msgList));
And this compiles with no warnings. Anyway when I run the program the value of countRecords(f_msgList) is 0, when the file have a bunch of data in it:
5a0203ff 360448
850203ff 393217
110203ff 425986
EDIT:
Here is the code where the file is opened or created:
FILE *f_msgList;
f_msgList = fopen("../message_queues.list", "a");
// if file does not exist then create one and check for errors
if (f_msgList == NULL) {
FILE *f_tmp;
f_tmp = fopen("../message_queues.list", "w");
if (f_msgList == NULL) {
fprintf(stderr, "Error occurred while creating the file! \n");
exit(1);
} else
f_msgList = f_tmp;
}
Problems
You opened the file in "append" mode. which does not let you read through the file.
If you want to write and then read the file, file pointer must be reset to the starting of the file.
feof(f_p) is worst way of checking whether file pointer is at end of the file.
Solution
Open File in "read" mode by 'r' or in append+read mode 'a+'.
if you are writing in to the file. reset it using rewind(f_p); after writing.
check out this way to read through the file :
int ret, ans, key;
while ((ret = fscanf(fp, "%x %i", &key, &ans))) {
if (ret == EOF)
break;
else
printf("%x %i \n",key, ans);
}
here integer ret is :
EOF, if the pointer is reached end of file.
0, if no input matched with the variable
(greater than 0), that is, number of matched variables with the file input
I want to check if there are any duplicates in a .txt file. I've wrote a code but it's not running. I'm not sure about opening the norep.txt file in "a+" mode. The idea is to put the first word of my text in the norep.txt file, then compare every word in the text.txt with the words in norep.txt and copy only the words I need in the file.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fd;
FILE *ft;
char aux[30];
char aux1[30];
int len;
fd = fopen("c:\\text.txt", "r");
if (fd == NULL) {
puts("Error");
}
ft = fopen("c:\\norep.txt", "a+");
if (ft == NULL) {
puts("Error");
}
fscanf(fd, "%s", aux);
fprintf(ft, "%s", aux);
rewind(fd);
rewind(ft);
while (!feof(fd)) {
fscanf(fd, "%s", aux);
while (!feof(ft)) {
fscanf(ft, "%s", aux1);
len = strcmp(aux, aux1);
if (len != 0) {
fprintf(ft, "%s", aux);
}
}
rewind(ft);
}
return 0;
}
You should flush the output file before you rewind it.
fflush - flush a stream or fflush
Of course, this will not fix your problem because:
Note below that the manual says that reposition operations are ignored so that your attempt to read will always find the end of file.
append: Open file for output at the end of a file. Output operations
always write data at the end of the file, expanding it. Repositioning
operations (fseek, fsetpos, rewind) are ignored. The file is created
if it does not exist.
What you should probably do is create an internal memory table that keeps all the unique entries and write it out to a new file after all processing is done. As you read the fd file, check the list and add a new entry if it is not already in the list. Then after you have finished processing fd, then and only then write out your list. Of course, this may be too big depending on the size of your data file.
You could append each unique entry to the output file as you go. but you would need to have some method of checking the previous entries without trying to read the output file.
The usual way to go about this is to read the input file word for word, store the necessary information in some way and then, after you have read all information from the file, write the desired output to the output file.
A rough skeleton of that approach might look like this:
int main()
{
const char *infile = "text.txt";
const char *outfile = "norep.txt";
FILE *in;
FILE *out;
char word[30];
// (1) Read all words
in = fopen(infile, "r"); // .. and enforce success
while (fscanf(in, "%29s", word) == 1) {
// store word somewhere
}
fclose(in);
// (2) Determine unique words somehow
// (3) Write out unique words
out = fopen(outfile, "w"); // .. and enforce success
for (i = 0; i < nunique; i++) {
fprintf(out, "%s\n", unique[i]);
}
fclose(out);
return 0;
}
The actual algorithm to fin the unique words is missing from this incomplete skeleton code.
If you really want to test the words in a file for uniqueness without using additional memory beyond the current word, you can open the input file twice, with independent file pointers. Then you can write a loop like so:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
const char *infile = "text.txt";
const char *outfile = "norep.txt";
FILE *in1;
FILE *in2;
FILE *out;
char word1[30];
char word2[30];
in1 = fopen(infile, "r");
in2 = fopen(infile, "r");
out = fopen(outfile, "w");
if (in1 == NULL || in2 == NULL || out == NULL) {
fprintf(stderr, "Could not open all required files.\n");
exit(1);
}
while (fscanf(in1, "%29s", word1) == 1) {
int count = 0;
while (fscanf(in2, "%29s", word2) == 1) {
if (strcmp(word1, word2) == 0) count++;
if (count > 1) break;
}
if (count == 1) fprintf(out, "%s\n", word1);
rewind(in2);
}
fclose(in1);
fclose(in2);
fclose(out);
return 0;
}
This will, of course, re-read the file as often as there are words in the file. Not a good approach to find the unique words in Moby-Dick. I recommend that you look into the memory-based approach.