I am trying to read ints from a txt file and store the first line into three variable and the rest into an array.
while(fgets(lineBuf, sizeof(lineBuf), inputFile) != NULL){
fscanf(inputFile, "%d %d %d", &pages, &frames, &requests);
printf("\n\nin loop to get first line variables:\n Pages: %d\n frames: %d\n requests: %d", pages, frames, requests);
}
Input file: the numbers with the first row being the first three and every row afterwards just being a single number.
8 12 4
4
3
4
...
when i run the program, it skips the 12 and 4.
It skips because you are reading the file with fgets as well, so fgets get
the first line, fscanf the second line but leaves the newline in the input
buffer, so fgets will read only an empty line, etc. It's a bad idea to mix
both reading function.
The best thing would be to read all lines with fgets and parse each line with
sscanf. Use the return value of sscanf to determine how many integer you've
read. From your input it seems that a line can have 1, 2 or 3 integers. So this
would do:
char line[1024];
while(fgets(line, sizeof line, inputFile))
{
int pages, frames, requests, ret;
ret = sscanf(line, "%d %d %d", &pages, &frames, &requests);
if(ret < 1)
{
fprintf(stderr, "Error parsing the line, no numbers\n");
continue;
}
if(ret == 1)
{
// do something with pages
} else if(ret == 2) {
// do something with pages & frames
} else if(ret == 3) {
// do something with pages, frames and requests
}
}
edit
based on your comments, of only the first line has 3 values and the rest of the
lines have one value each, then you can simplify the code like this:
#include <stdio.h>
int parse_file(const char *fname, int *pages, int *frames, int *request, int *vals, size_t size)
{
size_t idx = 0;
if(fname == NULL || pages == NULL || frames == NULL
|| request == NULL || vals == NULL)
return -1;
FILE *fp = fopen(fname, "r");
if(fp == NULL)
{
fprintf(stderr, "Cannot open %s\n", fname);
return -1;
}
if(fscanf(fp, "%d %d %d", pages, frames, request) != 3)
{
fprintf(stderr, "Wrong format, expecting pages, frames and requests\n");
fclose(fp);
return -1;
}
// reading all other values and storing them in an array
while((idx < size) && (fscanf(fp, "%d", vals + idx) == 1)); // <-- note the semicolon
fclose(fp);
return idx; // returning the number of values of the array
}
int main(void)
{
int pages, frames, request, vals[100];
int num = parse_file("/your/file.txt", &pages, &frames, &request,
vals, sizeof vals / sizeof vals[0]);
if(num == -1)
{
fprintf(stderr, "Cannot parse file\n");
return 1;
}
// your code
return 0;
}
Related
I have this file called pageRankList that contains url, number of outgoing links, page rank in that order.
if I want to get the pageRank of a given URL. How could I do this with fscanf or other functions?
url23 4 0.0405449
url31 3 0.0371111
url22 5 0.0300785
url34 4 0.0288782
url21 2 0.0247087
url11 3 0.0235192
url32 2 0.0227647
this is what I have so far but when I run it gives me a SEGV on unknown address error and I can't figure out why :(
static double getPageRank(char *url) {
double pageRank = 0;
FILE *fp = fopen("pageRankList.txt", "r");
char str[1000];
int counter = 0;
while (fscanf(fp, " %98s", str) != EOF) {
if (strcmp(url, str) == 0) {
counter++;
continue;
}
if (counter == 2) {
pageRank = atof(str);
printf("%f\n", pageRank);
break;
}
}
fclose(fp);
return pageRank;
}
fscanf(fp, " %98s", str)
This will stop reading when it hits a white space. It might be better to read all three things (url, number of outgoing links, page rank) at once. I would read a whole line at a time and then use sscanf on that:
static double getPageRank(const char* url)
{
FILE* fp = fopen("pageRankList.txt", "r");
if (!fp) return -1;
char str[1000];
double pageRank = -1;
while (fgets(str, sizeof(str), fp)) { // Read line
int number;
char line_url[100];
// Try to parse line
if (sscanf(str, "%99s %d %lf", line_url, &number, &pageRank) == 3) {
if (strcmp(url, line_url) == 0) {
break;
}
}
}
fclose(fp);
return pageRank;
}
*Note this works as long as url has no spaces.
I'm kinda new to programming so sorry for a stupid question. I've been tasked to read first two lines (numbers) and store them as variable n, and the other one in m. Other numbers bellow those two lines need to be read and store it in a dynamic array (malloc to be exact). Each line has exactly one number. I'm having trouble trying to accomplish this.
Here's my code so far:
#include <stdio.h>
#define MAX_LINE 5
int main() {
FILE* in;
FILE* out;
int n, m, list = (int*)malloc(9 * sizeof(int));
in = fopen("ulazna.txt", "r");
out = fopen("izlazna.txt","w");
if ((in && out) == NULL)
{
printf("Error opening the file...");
return -1;
}
while (fscanf(in, "%d\n", &m) != EOF)
{
fscanf(in, "%d\n", &n);
fscanf(in, "%d\n", &m);
printf("First two: %d %d", n, m);
}
//free(list);
fclose(in);
fclose(out);
return 0;
}
File ulazna.txt has:
3
3
This works as intended but when I write:
3
3
1
2
3
4
5
6
7
8
9
My program prints random numbers from this file.
So, I need to read 3 and 3 into n and m. Then, from 1 to 9 into the array list.
Thanks for help in advance :)
Dynamic array size
If you want to dynamically allocate memory for the list, you would have to count the number of lines in the file first.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n, m;
/* open the file for reading text using "r" */
FILE *file_in = fopen("ulazna.txt", "r");
if (!file_in) { /* same as `file_in == NULL` */
printf("Failed to open file\n");
return EXIT_FAILURE;
}
int lines = 0; /* number of lines */
int c; /* return value of `fgetc` is of type `int` */
/* go through each character in the file */
while ((c = fgetc(file_in)) != EOF) {
/* increment the number of lines after every line break */
if(c == '\n')
++lines;
}
/* reset pointer to start of file */
rewind(file_in);
/* check the return value of `fscanf` */
if (fscanf(file_in, "%d\n", &n) != 1 ||
fscanf(file_in, "%d\n", &m) != 1) {
printf("File contains invalid line\n");
return EXIT_FAILURE;
}
printf("First two: %d %d\n", n, m);
/* no need to cast `malloc`, because it returns `void *` */
int *list = malloc(lines * sizeof(int));
for (int i = 0; i < lines - 2; ++i) {
/* check the return value of `fscanf` */
if (fscanf(file_in, "%d\n", &list[i]) != 1) {
printf("File contains invalid line\n");
return EXIT_FAILURE;
}
printf("%d\n", list[i]);
}
free(list); /* always free memory allocated by malloc */
fclose(file_in);
return EXIT_SUCCESS;
}
Fixed array size
If you already know that the number of lines in the file is going to be 11, the array has a length of 9 and there is no need to dynamically allocate memory. But because your assignment requires it, I have implemented malloc.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n, m;
/* open the file for reading text using "r" */
FILE *file_in = fopen("ulazna.txt", "r");
if (!file_in) { /* same as `file_in == NULL` */
printf("Failed to open file\n");
return EXIT_FAILURE;
}
/* check the return value of `fscanf` */
if (fscanf(file_in, "%d\n", &n) != 1 ||
fscanf(file_in, "%d\n", &m) != 1) {
printf("File contains invalid line\n");
return EXIT_FAILURE;
}
printf("First two: %d %d\n", n, m);
/* the array has a fixed size of 9 */
const int size = 9;
int *list = malloc(size * sizeof(int));
/*
* If you do not have to use malloc, remove the
* above line and uncomment the following line:
*
* int list[size];
*/
for (int i = 0; i < size; ++i) {
/* check the return value of `fscanf` */
if (fscanf(file_in, "%d\n", &list[i]) != 1) {
printf("File contains invalid line or has to few lines\n");
return EXIT_FAILURE;
}
printf("%d\n", list[i]);
}
fclose(file_in);
return EXIT_SUCCESS;
}
int main() {
FILE *fp = fopen("fileA.txt", "r"); /* read file */
int i = 0;
char name[200][100];
char goods[200][100];
char qty[200][100];
char temp[200][100];
int x = 0;
int result;
while (!feof(fp)) {
fscanf(fp, "%[^,] , %[^,] , %s " , name[i], item[i], qty[i]); /*get file content and store in array */
if (strcmp(item[i], "Football") == 0) { /* only select Football */
temp[x][x] = qty[i];
if (x > 0) {
if (strcmp(temp[x][x], temp[x + 1][x + 1]) > 0) { /*compare who has more football qty */
result = x; /*output the person who have more football*/
}
}
x = x + 1;
}
}
printf("%s is team leader in class.\n", name[result]);
fclose(fp);
getchar();
return 0;
}
Hi all, I don't know why the result not correct.
I want to find out who has more football and print out his/her name.
Seems something wrong on if (strcmp(temp[x], temp[x + 1]) > 0)
I am not clearly on using pointer and address.
the content in the text file are:
Alice,Eating,001
Kitty,Football,006
Ben,Swimming,003
May,Football,004
And I expect the result is :
Kitty is team leader in class.
Thank you.
There are multiple problems in your code:
you do not test if the file is properly open.
you cannot properly parse a file with while (!feof(fp)) {. You should iterate for as long as fscanf() returns 3, or preferably read the input line by line and parse it with sscanf().
you do not tell fscanf() the maximum number of characters to store into the destination arrays. This may cause undefined behavior for invalid input.
you do not increment i for each line read. Every line of input overwrites the previous one.
you do not check if there are more than 200 lines. Undefined behavior in this case.
Your test to find the football fan with the highest quantity is broken: no need for a 2D array here, just keep track of the current maximum and update it when needed.
Here is a modified version:
#include <stdio.h>
int main() {
FILE *fp = fopen("fileA.txt", "r"); /* read file */
char buf[300];
char name[200][100];
char goods[200][100];
char qty[200][100];
int i, qty, max_qty = 0, result = -1;
if (fp == NULL) {
fprintf(stderr, "cannot open file\n");
return 1;
}
for (i = 0; i < 200; i++) {
if (!fgets(buf, sizeof buf, fp))
break;
if (sscanf(buf, " %99[^,], %99[^,],%99s", name[i], item[i], qty[i]) != 3) {
fprintf(stderr, "invalid input: %s\n", buf);
break;
}
if (strcmp(item[i], "Football") == 0) { /* only select Football */
qty = atoi(qty[i]);
if (result == -1 || qty > max_qty) {
result = i; /*store the index of the person who have more football */
}
}
}
if (result < 0)
printf("no Football fan at all!\n");
else
printf("%s is team leader in class with %d in Football.\n", name[result], max_qty);
fclose(fp);
getchar();
return 0;
}
Above Code is not clear as what you want to do in this code block
if ( strcmp(temp [x], temp [x+1]) > 0 ){ /* when matches, accessing temp[x+1] results in undefined behaviour */
result = x;
}
also why char *temp[200][100]; as to store qty[i], char *temp is enough or you can take char temp[200][100];
Here is somewhat better one as requirement is not clear.
int main() {
FILE *fp= fopen("fileA.txt","r"); /* read file */
if(fp == NULL) {
/* not exist.. write something ?? */
return 0;
}
char name [200][100],goods[200][100],qty[200][100],temp[200][100];
int x = 0,result = 0, i = 0;
while ((fscanf(fp, "%[^,] , %[^,] , %s " , name[i], goods [i], qty[i])) == 3) {
if (strcmp(goods[i] , "Football") == 0){
strcpy(temp[x],qty[i]);
if ( strcmp(temp [x], temp [x+1]) > 0 ) { /* UB ? */
result = x;
x+=1;
}
}
}
printf("%s is team leader in class. \n", name[result]);
fclose(fp);
getchar();
return 0;
}
I'm trying to read the number of a txt file like this:
input=20
output=10
hidden=5
....
I tried with this code:
char line[30];
char values[100][20];
int i = 0;
FILE *fp;
fp = fopen("myFile.txt", "r");
if(fp == NULL)
{
printf("cannot open file\n");
return 0;
}
while(fgets(line, sizeof(line), fp) != NULL)
{
sscanf(line, "%[^=]", values[i])
printf("%s\n", values[i]);
i++;
}
fclose(fp);
But I obtain only the first word and never the number after the =.
I get
input
output
etc
instead of
20
10
5
etc
How can I get the number??
This line
sscanf(line, "%[^=]", values[i]);
means "read everything up to, but not including, the = sign into values[i]".
If you are interested in the numeric part after the equal sign, change the call as follows:
sscanf(line, "%*[^=]=%19s", values[i]);
This format line means "read and ignore (because of the asterisk) everything up to, and including, the equal sign. Then read a string of length of up to 19 characters into values[i]".
Demo.
Don't use sscanf() for that, redeclare values to store the integers like
int values[LARGE_CONSTANT_NUMBER];
and after fgets() just use strchr
char *number;
number = strchr(line, '=');
if (number == NULL)
continue;
number += 1;
values[i] = strtol(number, NULL, 10);
you could also use malloc() and realloc() if you wish, to make the values array dynamic.
Try it if you like
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char line[100];
int values[100];
int i;
FILE *fp;
size_t maxIntegers;
fp = fopen("myFile.txt", "r");
if (fp == NULL)
{
perror("cannot open file\n");
return 0;
}
i = 0;
maxIntegers = sizeof(values) / sizeof(values[0]);
while ((fgets(line, sizeof(line), fp) != NULL) && (i < maxIntegers))
{
char *number;
number = strchr(line, '=');
if (number == NULL) /* this line does not contain a `=' */
continue;
values[i++] = strtol(number + 1, NULL, 10);
printf("%d\n", values[i - 1]);
}
fclose(fp);
return 0;
}
with this technique you avoid unecessarily storing the number as a string.
I'm writing a practice program to read integers from a file and sort them. I'm a little confused about file IO in C. What i have so far is below, I was hoping someone could take a look at it and offer any corrections/suggestions if they have any...
// TODO: Open input file and do same as above
char *mode = "r";
FILE *fp = fopen(inputFile, mode);
if(fp == NULL){
fprintf(stderr, "Can't open input file!");
exit(1);
}
// Load the numbers into a buffer and get a count
int buffer[100];
int count = 0;
while(fscanf(fp, "%d", &buffer[count]) == 1) {
count++;
}
// Initialize the array with the proper size
integers = (int*)malloc(sizeof(count*sizeof(int)));
// Load the integers into the array
rewind(fp);
for(int i = 0; i < count; i++){
if(fscanf(fp, "%d", &integers[count] != 1)){
fprintf(stderr, "Error loading integers into array");
exit(1);
}
}
fscanf() returns number of elements successfully read so check against the required number of elements to be read and in your case you can just read values to your array and increment index. Later use the value of index to allocate memory.
int *temp;
integers = malloc(sizeof(int)));
while(fscanf(fp, "%d", &integers[index]) == 1)
{
index++;
temp = realloc(integers,sizeof(int) * (index+1));
if(temp != NULL)
integers = temp;
}