While looping to end of file? - c

#include <stdio.h>
#include <stdlib.h>
//#define true 0
typedef struct
{
char currency[8];
int exchangerate;
} randT;
void main()
{
int i, num;
char currency1[8], ch;
FILE *file = fopen("address", "r");
randT name[7];
while(fscanf(file, "%i", &name[i].exchangerate) != EOF)/*I think this is where my problem is*/
{
fscanf(file, "%s %i", &name[i].currency, &name[i].exchangerate);
//printf("%s %i\n", currency1, num);
//if (fscanf(file, "%i", &currency1) == EOF) break;
printf("%s %i\n", name[i].currency, name[i].exchangerate);
i++;
}
fclose(file);
}
It is giving segmentation fault(core dumped) and i am fairly new to the fscanf functions and such. Please help!
my text file looks like this:
jeff 4
jina 5
jeffrey 6
jinna 7
jeffu 8
jinina 9
jeffz 10

The cause of the crash is that you need to initialize int i = 0;. As you have it, i is indeterminate, so probably name[i] is a massively out-of-bounds access.
For the fscanf, you have mostly the right idea about the loop, except instead of checking != EOF it's better to check == 1 or however many items you were reading. If the file contains something that can't be processed as a number, then fscanf will not return EOF.
However this is not the right way to read your particular file. You read %i then %s %i every time around, but your file only contains a string and an int. Change to:
while ( 2 == fscanf(file, "%7s %i", name[i].currency, &name[i].exchangerate) )
Also after doing i++ you need to check that i has not gone out of bounds (i.e. it's less than 7).
Note that name[i].currency decays to pointer to char - you shouldn't put & on it. Also you should use the length specifier to avoid running over the end of the array.
I would use the loop structure:
for (num_read = 0; num_read < sizeof name / sizeof name[0]; ++num_read)
{
if ( 2 != fscanf(file,.....
break;
printf(....
}

Related

reading data from a file after skiping the header

I'm trying to read numbers from a file, but first i gotta skip a header, this is a small code that only serves the purpose of testing the function, now...the function to skip part of the file works fine but when i try and read somthing from the file after i get a seg fault and the error code that means Status_acces_violation, but i just can't seem to find my mistake
The info in the file is always gonne be like this
Ex:
P5
256 789
125
125 236 789 ...(a bunch of numbers)
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *salt_header(FILE *poza){
char gunoi1[2];
fscanf(poza, "%s", gunoi1);
printf("%s\n", gunoi1);
int gunoi2;
fscanf(poza, "%d ", &gunoi2);
printf("%d ", gunoi2);
fscanf(poza, "%d", &gunoi2);
printf("%d\n", gunoi2);
fscanf(poza, "%d", &gunoi2);
printf("%d\n", gunoi2);
return poza;
}
int main()
{
FILE *poza;
char gunoi1[2], *nume;
nume = malloc(256 * sizeof(char *));
if(nume == NULL)
exit(-11);
scanf("%s", nume);
poza = fopen(nume, "r");
if(poza == NULL){
printf("Failed to open file\n");
exit(-1);
}
poza = salt_header(poza);
int numar;
for(int i = 0; i < 3; i++){
fscanf(poza, "%d", &numar);
printf("%d ", numar);
}
fclose(poza);
free(nume);
return 0;
}
char gunoi1[5]; // "P5" : 2 bytes , "\n" : 1 byte , "\0" : byte
just can't seem to find my mistake
In *scanf(), do not use "%s" without a width.
fscanf(poza, "%s", gunoi1); overflows char gunoi1[2]; as it is too small to store string "P5" leading to undefined behavior (UB). Remember a string always has a trailing null character, else it is not a string.
Also always check the return value of input functions.
A simple alternative, if the first line length is sane:
char buf[1000];
if (fgets(buf, sizeof buf, poza)) {
; // Successfully read the first line.
}

C: writing content of array to txt file

im trying to implement the number guessing game. The game itself works fine. But now I want to add a function which safes the score of the last game (Number of trys and guessed number) in the leaderboard.txt file.
I haven't finished the saveScore method yet, I don't need help with implementing the rest. I wan't to read the data from the file, add the new line and sort it from least to most trys. But I only wan't to save the top 10 of all time.
I need some help to get the following code running. One problem is the code doesn´t even terminate.
I think all the problems are within the saveScore method. (line 18 -25)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define max_length 300
void saveScore(int guess, int randNumber) {
FILE *datei;
datei = fopen("leaderboard.txt", "wb");
char lines[max_length];
char leaderboard[10][max_length];
int line = 0;
while (fgets(leaderboard[line], sizeof(lines), datei) != NULL){
line++;
}
leaderboard[line][max_length] = ("%d, %d", guess, randNumber);
fwrite(leaderboard, sizeof(char), sizeof(leaderboard), datei);
fclose(datei);
}
void startGame(){
int guess = 1;
int randNumber;
int uInput;
randNumber = (rand()%100)+1;
printf("%d", randNumber);
do {
printf("Guess the number between 1-100: \n");
scanf("%d", &uInput);
if (uInput < randNumber){
printf("the number you are looking for is higher.\n");
}
else if (uInput > randNumber){
printf("the number you are looking for is lower.\n");
}
else {
printf("Jackpot it was your %d. try.", guess);
}
guess++;
} while (randNumber != uInput);
saveScore(guess, randNumber);
char playAgain = 'j';
printf("Try Again (j/n): \n");
scanf(" %c", &playAgain);
if (playAgain == 'j') {
startGame();
}
printf("Thank you for playing.");
}
int main() {
srand(time(NULL));
startGame();
return 0;
}
I appreciate any help.
Best Enno
This loop has the problem of being able to overflow leaderboard if line ever reaches 10.
while (fgets(leaderboard[line], sizeof(lines), datei) != NULL){
line++;
}
This line
leaderboard[line][max_length] = ("%d, %d", guess, randNumber);
has a few problems. [max_length] would be one past the end of the buffer, but with that said, it is not needed and the assignment as a whole is incorrect. To perform string interpolation, use a function such as sprintf.
Aside from the fact that you only open the file for writing, the primary problem is that
fwrite(leaderboard, sizeof(char), sizeof(leaderboard), datei);
will write the entire contents of leaderboard to the file. This includes the garbage values that exist towards the end of each array, after each string. fgets will then read those garbage values later.
You should stick to reading and writing binary or text, but do not mix them. If you use fgets, use fputs (or similar) to write the text. Conversely, if you use fwrite, use fread to read the binary data.
Here is a basic, cursory snippet using text functions, where we:
open the file for reading
read our lines into the array
close the file
add our new score to the array
sort our array using qsort
open the file for writing
write our lines
close the file
The trick here is leaderboard has an additional slot, so that there is always room for our newest score. After sorting, we only write at most MAX_ENTRIES entries to the file, meaning if the array is full we ignore the worst score.
#define MAX_ENTRIES 10
#define MAX_LENGTH 300
#define SAVE_FILE "leaderboard.txt"
int compare(const void *ap, const void *bp) {
const char (*a)[MAX_LENGTH] = ap;
const char (*b)[MAX_LENGTH] = bp;
int av, bv;
sscanf(*a, "%d", &av);
sscanf(*b, "%d", &bv);
return (av > bv) - (av < bv);
}
void saveScore(int guess, int randNumber) {
char leaderboard[MAX_ENTRIES + 1][MAX_LENGTH] = { 0 };
size_t entries = 0;
FILE *file = fopen(SAVE_FILE, "r");
if (file) {
while (entries < MAX_ENTRIES &&
fgets(leaderboard[entries], sizeof *leaderboard, file))
entries++;
fclose(file);
}
sprintf(leaderboard[entries], "%d %d\n", guess, randNumber);
entries++;
qsort(leaderboard, entries, sizeof *leaderboard, compare);
file = fopen(SAVE_FILE, "w");
if (file) {
for (size_t i = 0; i < entries && i < MAX_ENTRIES; i++)
fputs(leaderboard[i], file);
fclose(file);
}
}

How to Read and Add Numbers from txt file in C

I am trying to make a program that reads numbers from a text file named numbers.txt that contains different numbers in each line.
For example:
8321
12
423
0
...
I have created this program, but it does not work properly. I have tried many things and don't know what to do. Can someone guide me in the right direction? Thank you!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 1000
int main(int argc, char *argv[]) {
char str[MAX_LEN];
FILE *pFile = fopen(argv[1], "r");
int num;
int sum = 0;
int count = 0;
if (pFile == NULL) {
printf("Error opening file.\n");
return 1;
}
while (!feof(pFile) && !ferror(pFile)) {
if (fscanf(pFile, "%d", &num) == 1) {
count++;
while (strcmp(fgets(str, MAX_LEN, pFile), "\0") == 0) {
printf("%s", str);
//sum = sum + (int)(fgets(str, MAX_LEN, pFile));
printf("\n");
}
}
}
fclose(pFile);
printf("count = %d \n", count);
printf("sum = %d \n", sum);
return 0;
}
strcmp(fgets(str, MAX_LEN, pFile),"\0") is wrong in many ways. For one, the argument of strcmp must be a string (which a null pointer isn't), but fgets returns NULL on error or end of file. You need to check that it didn't return NULL and then you can compare the string in str. However, there is no need to strcmp against "\0" (or, in this case equivalently, "") to detect the end of file, because that's when fgets returns NULL.
Another issue is that you are reading with both fscanf and fgets – pick one and stick with it. I recommend fgets since it's generally easier to get right (e.g., on invalid input it's a lot harder to recover from fscanf and make sure you don't get stuck in an infinite loop while also not losing any input). Of course you need to parse the integer from str after fgets, though, but there are many standard functions for that (e.g., strtol, atoi, sscanf).
Don't use !feof(file) as the loop condition (see, e.g., Why is “while ( !feof (file) )” always wrong?). If you are reading with fgets, end the loop when it returns NULL.
You can use strtok to split the numbers in each line, then using atoi function to convert string to int.
For example:
while(fgets(str, MAX_LEN, pFile)) {
// if the numbers are separated by space character
char *token = strtok(str, " ");
while(token != NULL) {
sum += atoi(token);
strtok(NULL, " ");
}
}
if there is only one number per line, you do not need to use strtok:
while(fgets(str, MAX_LEN, pFile)) {
sum += atoi(str);
// OR
sscanf(str,"%d\n", &new_number)
sum += new_number;
}
Your program has multiple problems:
no test if a command line argument was passed.
while (!feof(pFile) && !ferror(pFile)) is always wrong to iterate through the file: feof() gives valid information only after a actual read attempt. Just test if the read failed.
if fscanf(pFile, "%d", &num) == 1) add the number instead of just counting the numbers.
strcmp(fgets(str, MAX_LEN, pFile), "\0") will fail at the end of the file, when fgets() returns NULL.
If the file only contains numbers, just read these numbers with fscanf() and add them as you progress through the file.
Here is a modified version:
#include <stdio.h>
int main(int argc, char *argv[]) {
FILE *pFile;
int num
int sum = 0;
int count = 0;
if (argc < 2) {
printf("Missing filename\n");
return 1;
}
if ((pFile = fopen(argv[1], "r")) == NULL) {
printf("Error opening file %s\n", argv[1]);
return 1;
}
while (fscanf(pFile, "%d", &num) == 1) {
sum += num;
count++;
}
fclose(pFile);
printf("count = %d \n", count);
printf("sum = %d \n", sum);
return 0;
}

I am completely new to C programming and keep getting a segmentation fault

This is for a hotel reservation system, that take a .txt file that contains lines of int string string int which it then reads and put into an array of type room... while scanning it keeps giving me segmentation fault... this is for class and i dont want a ready code to leech of but i just dont get why i keep getting segmentation... :/
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int num;
char first[100];
char last[100];
int type;
}room;
int main (int argc, char ** argv){
FILE * myFile;
if(argc !=2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return EXIT_FAILURE;
}
myFile = fopen(argv[1],"r");
if (myFile==NULL){
fprintf(stderr, "no open!!\n");
return EXIT_FAILURE;
}
// counter to add elements to my array
int i = 0;
char c;
//array of room with the 150 rooms in it...
room * rooms = malloc(150 * sizeof(room));
while ((c = getc(myFile)) != EOF ){
fscanf(myFile, "%d", rooms[i].num);
printf("the room num is: %d", rooms[i].num);
fscanf(myFile, "%s", rooms[i].first);
fscanf(myFile, "%s", rooms[i].last);
fscanf(myFile, "%d", rooms[i].type);
i++;
}
fclose(myFile);
}
Here is what i fixed in my code and worked but it is literally skipping the fist integer in the .txt file that it reads from... it just reads a zero when it should be a 1 so i noticed that the "(c = getc(myFile)) != EOF" was my problem, it is skipping the first integer it is supposed to read :/
while ((c = getc(myFile)) != EOF ){
fscanf(myFile, "%d", &rooms[i].num);
fscanf(myFile, "%s", rooms[i].first);
fscanf(myFile, "%s", rooms[i].last);
fscanf(myFile, "%d", &rooms[i].type);
printf("the room num is: %d and is occupied by %s %s and it is a %d\n", rooms[i].num, rooms[i].first, rooms[i].last, rooms[i].type);
i++;
}
The .txt file's first line is as follows:
1 carri alston 0
In your code
fscanf(myFile, "%d", rooms[i].num);
should be
fscanf(myFile, "%d", &rooms[i].num);
same with the type thing.
Along with that, you should always check the return value of fscanf() to ensure proper scanning.
also, you need to put a check on the value of i so that it should not access out of bound memory.

How to read in a text file of tab-separated integers in C?

I have a file of simply tab-separated integers (a .txt file) and I wish to read them in with just C, line by line. So, say each line has 5 integers. How can I accomplish this?
My first attempt was as follows. It was just to read in a single integer, but even that didn't work:
FILE *fp;
char blah[255];
int *some_int;
fp = fopen("test.txt", "rt");
while (fgets(blah, 255, fp) != NULL)
{
sscanf(blah, "%d", some_int);
printf("%d\n", *some_int);
}
Here's a way no one else suggested, that doesn't use fscanf so you can have sane error handling:
char buffer[BUFSIZE];
size_t size = 5;
int *data = malloc(size * sizeof *line);
if(line == NULL) error();
while(fgets(buffer, sizeof buffer, fp)
{
size_t i = 0;
char *next = buffer;
while(*next && *next != '\n')
{
data[i++] = strtol(next, &next, 0);
// check for errors
}
}
Basically, instead of trying to use *scanf's "%d" to read characters, use the function it (probably) calls to do the conversion: strtol. Where *scanf goes through the string to match the format string but doesn't let you "save your place" in between function calls, strtol does, which is what you need to read an arbitrary number of integers.
I haven't written all your code for you - you have to do the hard error handling. Possible errors include:
i == size, in which case you can try to make data bigger with realloc. Alternately, you could loop through the buffer and count how many numbers there are beforehand, then allocate that many so you don't need to reallocate later.
fgets didn't read the entire line (check that the last character before '\0' is '\n'). In this case you'll probably want to refill the buffer and keep reading numbers. Be careful in this case - you'll likely need to go back and recalculate the last number - fgets might have cut it off. (This is one disadvantage to using fgets.)
Erroneous input - handle however you like.
#include <stdio.h>
int main(){
FILE *fp;
int scanned = 0;
int some_ints[5];
fp = fopen("test.txt", "r");
while ((scanned = fscanf(fp, "%d %d %d %d %d", some_ints, some_ints+1, some_ints+2, some_ints+3, some_ints+4)) != EOF) {
if(scanned ==5){
printf("%d %d %d %d %d\n", some_ints[0], some_ints[1], some_ints[2], some_ints[3], some_ints[4]);
}
else {
printf("Whoops! Input format is incorrect!\n");
break;
}
}
}
I'd do something like this:
int storedVals[MAX_STORED_VALS];
int bf;
int ii=0;
while (!feof(fp) && ii<MAX_STORED_VALS) {
if (fscanf(fp," %d",&bf)) {
storedVals[ii++]=bf;
}
}
fscanf automatically does white space trimming. So as long as there's a space in your scan string, it'll get rid of zero or more \t (tabs) and \n (newlines) to find the next integer. Of course, this doesn't do much by way of error correction.

Resources