Trying to read a two numbers from a text file - c

I am trying to read two numbers from a text file. I used strtok, and the delimiter is " ". The text file (named data.txt) file has only two numbers, the line is "3 5". But the program crashes... any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
FILE *data;
data = fopen("data.txt", "r");
int m, n;
char *line, *number;
while(!feof(data))
{
fscanf(data, "%s", line);
number = strtok(line, " ");
m = atoi(number);
number = strtok(NULL, " ");
n = atoi(number);
}
}

line is a uninitialized pointer, it doesn't point to any valid memory location so you can't use it to store data, use an array instead.
while(!feof(data)) is not what you'd want to use to control your read cycle.
Use fgets/sscanf to parse the values, simple and easy way to do it:
FILE *data;
data = fopen("data.txt", "r");
int m, n;
char line[32];
if (data != NULL)
{
while (fgets(line, sizeof line, data)) // assuming that you want to have more lines
{
if(sscanf(line, "%d%d", &m, &n) != 2){
// values not parsed correctly
//handle parsing error
}
}
}
Or as #chux pointed out, to detect extra junk on the line:
char end;
if(sscanf(line, "%d%d %c", &m, &n, &end) != 2) {
// if more characters exist on the line
// the return value of sscanf will be 3
}
If the values in the file can be outside the range of an int consider using strtol instead of sscanf.

Related

How to fscanf only the elements that we want?

I want to do fscanf on a .txt file, here's how it looks
7 6
[1,2]="english"
[1,4]="linear"
[2,4]="calculus"
[3,1]="pe"
[3,3]="Programming"
I want to take only the 2 numbers in the brackets, the first is day, and the second is session, and I also want to take the string subject
Here's the whole code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
FILE *inputFile, *outputFile;
int day;
int session;
char subject[15];
inputFile = fopen("Schedule.txt", "r");
if (inputFile == NULL) {
puts("File Schedule.txt Open Error.");
}
fscanf(inputFile, "%d %d %s", &day, &session, subject);
printf("%d", day);
fclose(inputFile);
return 0;
}
Apparently the fscanf does not work the way i want it to.
The expected output is storing the numbers to the variables I have assigned
What actually happened is it only printed out '7'
An approach reading line by line and using sscanf
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LINEBUFSIZE 500
int main(){
FILE *inputFile;
char line[LINEBUFSIZE];
inputFile = fopen("Schedule.txt", "r");
if (inputFile == NULL) {
puts("File Schedule.txt Open Error.");
}
while (fgets(line, LINEBUFSIZE, inputFile)) {
int day;
int session;
char subject[15];
int r;
// %14s because char subject[15] (14 char + null)
r = sscanf(line, "[%d,%d]=%14s", &day, &session, subject);
if (r != 3)
// Could not read 3 elements
continue;
printf("%d %d %s\n", day, session, subject);
}
return 0;
}
to take only the 2 numbers in the brackets, the first is day, and the second is session, and I also want to take the string subject
(I leave OP to handle first line "7 6\n".)
Drop all fscanf() calls. Use fgets() to read a line and then parse.
char buf[100];
if (fgets(buf, sizeof buf, inputFile)) {
// Parse input like <[1,2]="english"\n>
int day;
int session;
char subject[15];
int n = 0;
sscanf(buf, " [%d ,%d ] = \"%14[^\"]\" %n",
&day, &session, subject, &n);
bool Success = n > 0 && buf[n] == '\0';
...
Scan the string. If entirely successful, n will be non-zero and buf[n] will pointer to the string's end.
" " Consume optional white spaces.
"[" Consume a [.
"%d" Consume optional spaces and then numeric text for an int.
"," Consume a ,.
"]" Consume a ].
"\"" Consume a double quote mark.
"%14[^\"]" Consume 1 to up to 14 non-double quote characters and form a string.
"%n" Save the offset of the scan as an int.

Read Line By Line Until Integer is Found C

Trying to create a program that takes in a text file and reads it line by line. It then finds the two integers that are on each line and adds them together. It then outputs the new line with the original string and total to a new text file. I need help adding the two integers, getting them from each line, and then putting the new line to a text file.
input text file
good morning hello 34 127
ann 20 45
10 11
fun program and you find the same 90 120
news paper said that 56 11
how do you like 20 5
line number 90 34
Outputs first like would look like: and then continue on
good morning hello 161
Code:
int processTextFile(char * inputFileName, char * outputFileName)
{
FILE *fp = fopen(inputFileName, "r");//open file to to read
char buff[1024];
char *p, *p1;
int num;
while (fgets(buff, 1024, fp)!=NULL)
{
printf("%s\n", buff);
while(scanf(buff, "%*[^0-9]%d", &num)== 1)
printf("%d\n", num);
//fscanf(fp, "%s", buff);
}
return 0;
}
EDIT!!!!::
So now that I've been able to accomplish this. How would I sort it by the number produced? for example:
Time is money 52
here I am 3
21
Would output to a new text file in order like
here I am 3
21
Time is money 52
My version using strcspn() is supposed to work with stdin for input and stdout for output. (so you can do executable <textfile >newtextfile)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
if (line[x]) {
errno = 0;
int n1 = strtol(line + x, &ptr, 10);
if (*ptr && !errno) {
errno = 0;
int n2 = strtol(ptr, &ptr, 10);
if (*ptr && !errno) {
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
}
return 0;
}
The same version without the error checking
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
int n1 = strtol(line + x, &ptr, 10);
int n2 = strtol(ptr, &ptr, 10);
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
}
return 0;
}
The approach should be:
open two files, one for input, one for output.
use sscanf() to read the input buffer.
scan the leading string, and then two number.
if previous sscanf() fails, only check for two number.
if either of the above scanning is success, print the sum to the output file.
A sample code, should look like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *fpin = fopen("ipfile", "r");//open file to to read
if (!fpin)
{
printf("Error in ipfile opening\n");
exit (-1);
}
FILE *fpout = fopen("opfile", "w");//open file to to write
if (!fpout)
{
printf("Error in opfile opening\n");
exit (-1);
}
char buff[1024] = {0};
char str[1024] = {0};
int num1 =0, num2= 0;
while (fgets(buff, 1024, fpin)!=NULL)
{
memset(str, 0, sizeof(str));
//printf("%s\n", buff);
if(sscanf(buff, "%[^0-9]%d %d", str, &num1, &num2)== 3)
fprintf(fpout, "%s %d\n", str, (num1+num2));
else if (sscanf(buff, "%d %d", &num1, &num2)== 2)
fprintf(fpout, "%d\n", (num1+num2));
}
return 0;
}
Note:
The above procedure, is a kind of workaround. If the data pattern in the file changes, lot of changes will be required to maintain a code like that. Instead of usinf sscnaf(), for a better and roubust approach, you should
read the line from file
start tokenizing the input buffer (strtok()) and check for ints as tokens (strtol()).
save the returned tokens and ints seperately.
once the strtok() returns NULL, you print the string tokens and the sum of the ints to the o/p file.
I intend not to change your code completely, so I just added some snippets for improvement.
int processTextFile(char *inputFileName, char *outputFileName) {
FILE *fp = fopen(inputFileName, "r");
FILE *out = fopen(outputFileName, "w");
char line[1024];
if (!fp) {
perror(inputFileName);
return;
}
while (fgets(line, sizeof(line), fp) != NULL) {
int num1 = 0, num2 = 0;
char textPart[1024] = "";
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) {
sscanf(line, "%d%d", &num1, &num2);
}
fprintf(out, "%s %d\n", textPart, num1 + num2);
}
fclose(fp);
fclose(out);
}
Explanation:
I scanned the text file, extracted the text part and the two ints. Since I noticed that the ints are placed at the end of each line, I just used sscanf() for that matter.
sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2);
Here, "%[a-zA-Z' ']%d%d" format specifiers means to get only alphabets and spaces.
Since it will only get letters and spaces, the line "10 11" in your input file won't be put to num1 and num2. Because the code inspects first for a string containing letters and spaces. Since 10 and 11 are not of the qualified types, then the line is just skipped.
That's why I added an if-else statement, which checks if sscanf wrote anything to memory. If sscanf returned 0, then it means that no text part is present. Just digits. So the program will scan the two digits.
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) ) {
sscanf(line, "%d%d", &num1, &num2);
}
I also added file checking for input file. It checks if file doesn't exist or can't be opened by the filestream.
if (!fp) {
perror(inputFileName);
return;
}
Here is the content of output file after execution:
good morning hello 161
ann 65
21
fun program and you find the same 210
news paper said that 67
how do you like 25
line number 124

Read a file then store numbers in array C

so I have this file called "score.txt" with contents
NAME
20
NAME2
2
And I'm using this code but it gets an error and I have no idea on how to put the integers from the file in an array.
int main(){
FILE* file = fopen ("score.txt", "r");
int i = 0;
fscanf (file, "%d", &i);
while (!feof (file))
{
printf ("%d ", i);
fscanf (file, "%d", &i);
}
fclose (file);
system("pause");
}
I'm only self learning and i've been trying to figure this out for 2hours already
The problem with using fscanf for input where some lines will fail the format is that the file will not be advanced per iteration of the while loop, so you get stuck.
You can get a solution by using fgets to grab the data and sscanf to grab the number:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
int i = 0;
int ret = 0;
char buf[50];
FILE *file = fopen("score.txt", "r");
if (file == NULL) {
fprintf(stderr,"Unable to open file\n");
exit(1);
}
while (fgets(buf,sizeof(buf),file)) {
ret = sscanf(buf,"%d",&i);
if (ret == 1) { // we expect only one match
printf("%d\n", i);
} else if (errno != 0) {
perror("sscanf:");
break;
}
}
fclose(file)
return(0);
}
This will output, for your input:
20
2
We check the output of sscanf as it tells us if the format has been matched correctly, which will only happen on the lines with integer, and not the 'NAME' lines. We also check for 'errno' which will be set to non-zero if sscanf encounters an error.
We used char buf[50]; to declare a char array with 50 slots, which fgets then uses to store the line its reading; however if the line is more than 50 chars in length it will be read in 50 char chunks by fgets, and you may not get the results you desire.
If you wish to store the integers you read into an array, you'll have to declare an array, then on each read assign a slot in that array to the value of the int you read i.e. int_array[j] = i (where j will have to change with each slot you use). I'll leave it as an exercise to implement this.

Issues with structs in C

I have an array in a struct. I'm reading from a file into a string. I use strtok to get the first few characters, and i want to pass the rest of the line into the struct, to eventually be passed into a thread. I'm getting the following error:
incompatible types when assigning to type char[1024] from type char *
Referring to the line indicated below with the comments. It probably has to do with how i'm trying to copy character arrays, but i'm not sure on a better way.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <linux/input.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
typedef struct
{
int period; //stores the total period of the thread
int priority; // stores the priority
char pline[1024]; // stores entire line of text to be sorted in function.
}PeriodicThreadContents;
int main(int argc, char* argv[])
{
//opening file, and testing for success
//file must be in test folder
FILE *fp;
fp = fopen("../test/Input.txt", "r");
if (fp == NULL)
{
fprintf(stderr, "Can't open input file in.list!\n");
exit(1);
}
char line[1024];
fgets(line, sizeof(line), fp);
//getting first line of text, containing
char *task_count_read = strtok(line," /n");
char *duration_read = strtok(NULL, " /n");
//converting char's to integers
int task_count = atoi(task_count_read);
int i = 0;
PeriodicThreadContents pcontents;
printf("started threads \n");
while (i < task_count)
{
fgets(line, sizeof (line), fp);
strtok(line," ");
if (line[0] == 'P')
{
char *period_read = strtok(NULL, " ");
pcontents.period = atoi(period_read);
printf("%d",pcontents.period);
printf("\n");
char *priority_read = strtok(NULL, " ");
pcontents.priority = atoi(priority_read);
printf("%d",pcontents.priority);
printf("\n");
printf("\n%s",line);
memcpy(&(pcontents.pline[0]),&line,1024);
printf("%s",pcontents.pline);
}
}
return 0;
}
C cannot handle strings as other languages do. C doesn't have string assignments or comparisons without using auxiliary functions.
In order to copy a string in a buffer you can use:
strcpy(pcontents.pline, line);
Or even (to have a warranty that your string is not longer than 1024 bytes):
memcpy(pcontents.pline, line, 1024);
pcontents.pline[1023] = '\0';
For other string operations check: http://www.gnu.org/software/libc/manual/html_node/String-and-Array-Utilities.html#String-and-Array-Utilities
You need to copy the chars from the buffer into pcontents.pline (assuming pcontents is a PeriodicThreadContents).
strcpy(pcontents.pline, strtok(NULL, " "));

How to read and store 2 float values seperated by a comma from a file into two arrays where each float is stored in one array

my text file format is this:
3.2 , 5.6
444.2 , 555
112.34 , 32.3
i want to read the above information present within file name file.txt and store it in two arrays a,b where a will have the float value before the comma and b will have the float value after the comma
Use fgets() in a loop to read each line. Then once you have the line, use sscanf() to scan out the two floating-point numbers, like so:
while(fgets(line, sizeof line, myfile) != NULL)
{
if(sscanf(line, "%f,%f", &a[i], &b[i]) == 2)
{
++i;
}
else
printf("Parse error in %s", line);
}
Note that the return value from sscanf() says how many conversions that succeeded. If it isn't two, we don't want to move forward in the array. Remember to make sure i is initialized to 0 before the loop, of course.
E.g.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DATA_SIZE 10
int main (void){
char filename[256] = "file.txt";
char input_line[128];
FILE *fp;
float a[DATA_SIZE], b[DATA_SIZE];
int i,j;
if(NULL==(fp=fopen(filename, "r"))){
perror("input file open");
return -1;
}
i=0;
while(NULL!=fgets(input_line, sizeof(input_line), fp)){
if(*input_line == '\n') continue;
a[i]=atof(strtok(input_line, " ,\n"));//ok even this ","
b[i]=atof(strtok(NULL , " ,\n"));
++i;
}
//check print
for(j=0;j<i;++j){
printf("a[%d]=%g, b[%d]=%g\n", j, a[j], j, b[j]);
}
return 0;
}

Resources