Jump to next line in .txt file in C - c

I need to make some actions from txt file.
What I was willing to do:
Calculate number of lines in txt
Open txt file
Iterate for each line
Iterate within each line and perform the task within it
Close file
Current code:
int lines(){
FILE *fp = fopen("somedata.txt","r");
int ch;
int count=0;
do{
ch = fgetc(fp);
if( ch== '\n') count++;
}
while( ch != EOF );
fclose(fp);
return count;
}
int main(){
int linesnum=lines();
FILE *fp = fopen("somedata.txt", "r");
if (fp == 0){
fprintf(stderr, "failed to open test0.txt\n");
exit(-1);
}
float areas[linesnum];
for (int j=0;j<linesnum;j++){
float array[150];
for (int i = 0; i < 150; i++){
fscanf(fp, "%f", &array[i]);
if (getc(fp) == (int)'\n'){
//that ends iteration for a line once it founds "\n"
//and assigns its value to temporary array
break;
}
}
//SOME TASK PERFORMED OVER HERE FOR EACH LINE lets say calculate average
if (getc(fp) == EOF){ //That's supposed to be end of iteration through lines
break;
}
}
fclose(fp);
return 0;
}
File is in format (max lines 1000, max elements in each line is 150).
Number of elements in each line is different, so if I make a big matrix of 1000x150, most of elements will be empty; that's why I don't want a matrix, and just simply want perform task for each line.
1 2 3 4 5 6
1 3 2 5 6 7 3 5
1 3 3 2 5 2 3
5 3 4 2 52 5 6
Well, I'm ending up with error Segmentation fault: 11 after performing task for 1st line.
I'm not sure how do I jump to next line after 1st iteration. That's the question.
Any thoughts?
UPDATE: Just had to get rid of EOF break thing in main():
if (getc(fp) == EOF){
break;
}

Something like this may work.
Read a line with fgets. The line must be large enough to hold the longest line.
Use a pointer to line and an offset to parse the values from the line.
%n will receive the number of bytes used by the sscanf so the pointer can be advanced to the next value.
char line[1500];
char *pline;
int used = 0;
int i = 0;
int linesnum = 0;
float array[150];
while ( fgets ( line, sizeof ( line), fp))) {
pline = line;
i = 0;
while ( ( sscanf ( pline, "%f%n", &array[i], &used)) == 1) {
pline += used;
i++;
if ( i >= 150) {
break;
}
}
linesnum++;
if ( linesnum >= 1000) {
break;
}
}

Related

Segmentation Fault while reading multiple lines from a text file character-by-character

I am trying to read lines from a file, one character at a time.
Input example:
5 2
2
1 3
2 4 5
3
Suppose I am trying to read the first line, then I am reading '5' first, then the space (' ') and then the '2', and then trying to store the two number in a array, which I am declarig using realloc because I don't know how many numbers will be there in a line before reading the line.
I only knwo the number of lines that will be present in the file numNodes.
I am trying to store the numbers in a 2D array, where each row will have differnet lengths.
Since I don't know th length of each line beforehand, I am allocating memory using realloc after reading each number.
Since the numbers can be more than one-digited, i am storing the characters in num character array and when i encounter a space(' ') or newline('\n'), I convert it to a number using atoi, and store it in the suitable row, after allocating memory to it using realloc.
here's my code
FILE *fp;
fp = fopen("input.txt","r");
char ch;
int numNodes = 5, i = 0;
int **adjList = (int **)malloc(numNodes*sizeof(int *));
int len = 0,j,k=0;
char num[4];
for(i=0;i<numNodes;i++)
{
adjList[i] = NULL;
printf("Node %d -> ",i+1);
do
{
//read =
fscanf(fp,"%c",&ch);
if(ch!=' ' && ch!='\n')
{
num[k]=ch;
k++;
}
else
{
k = 0;
len++;
adjList[i] = (int *)realloc(adjList[i],sizeof(int)*len);
adjList[i][len-1] = atoi(num);
for(k=0;k<4;k++)
num[k]='0';
}
}
while(ch!='\n');
for(j=0;j<len;j++)
printf("%d ",adjList[i][j]);
printf("\n");
len = 0;
}
However, I am getting Segmentation Fault (core dumped) on the last line, that is, after 2 4 5 gets printed.
Any help is appreciated, as to, why this error is occuring on the last line?
EDIT :
Changed ch to &ch in fscanf line
Changed ch[0] to ch(if statement)
Added adjlist[i] = NULL before do...while loop
fscanf(fp,"%c",&ch);
if(ch!=' ' && ch!='\n')
{
num[k]=ch;
k++;
}
else
{
k = 0;
len++;
adjList[i] = (int *)realloc(adjList[i],sizeof(int)*len);
adjList[i][len-1] = atoi(num);
for(k=0;k<4;k++)
num[k]='0';
}
When you finish reading one number k will be 4.
for(k=0;k<4;k++)
num[k]='0';
And you start reading the next number with k >= 4 thus access out of bound for num .
num[k]=ch;
k++;
Also you need to terminate the num with \0 char to be used with atoi.
num[k] = '\0';
adjList[i][len-1] = atoi(num);

how to get the number of integer in a file with empty space in it

number.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14
For instance, I have the above text file. I would like to get the number of integer in the file (which is 14 in this case), and pass every integer into an array.
what I did is
int count = 0;
int i = 0;
while ( 1 )
{
int c = fgetc( fp );
if ( c == EOF || c == '\n' )
{
if ( c == EOF ) break;
}
else if(c ==' ')
{
++count;
--count;
}
else
{
++count;
arr[i] = c-48; // This line give me the wrong number so I subtract it by 48
++i;
}
}
In the case, the count will only get the correct value when there is no double digits number in the file(such as 10 11 12 13). Otherwise, it does not work.
I also tried to use fscanf to store every integer in an array, then get the length of the array. That does not work since I have to define the length of the array first and there is no way I can do that.
My question is how to deal with the double digits number in the file in order to get the right value. Is there a better to do that? Can someone help? Thanks in advance.
You can just read the integers with fscanf(), and every time a number is found, increment a counter.
Something as simple as this could work:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
int num;
size_t count = 0;
fp = fopen("somenumbers.txt", "r");
if (!fp) {
fprintf(stderr, "Error reading file\n");
return 1;
}
while (fscanf(fp, "%d", &num) == 1) {
count++;
}
printf("number of digits = %zu\n", count);
fclose(fp);
return 0;
}

read a file and save as a matrix

i have a file like that :
1 100
2 200
3 300
4 400
1
i want to save it as a matrix and i want to save NULL if there is no second number !
i tried to write the program but it does not work correctly !
#include<stdio.h>
int main() {
int k=0 ,i,j , arr[100][100];
FILE *in= fopen("file.txt","r");
char line[1000];
while(fgets(line,1000,in) !=NULL) k++;
fgets(line,1000,in);
for (i=0;i<k;i++){
for (j=0;j<2;j++){
int tmp ;
fscanf(in ,"%d", &tmp) ;
arr[i][j] = tmp ;
}
}
fclose(in);
return 0; }
Two major problems:
The first is that the first loop will read all lines, even the one with the single number on the line. That means the lonely fgets call will not do anything, and more importantly that the value of k will be wrong.
The second problem is that once you read all data from the file, you don't go back to the beginning of the file, instead you continue to try and read from beyond the end of the file.
The first problem can be solve by skipping the second fgets call, and decreasing k by one.
The second problem can be solved by calling rewind after you counted the number of lines.
Also when you actually read the numbers, you don't need the inner loop, just do e.g.
scanf("%d %d", &arr[i][0], &arr[i][1]);
Actually, you don't need the first line-counting loop at all, you can do it all in a single loop, by using fgets and sscanf and then checking the return value of sscanf. So your program could look something like
#include <stdio.h>
int main(void)
{
int values[100][2];
FILE *input = fopen("file.txt", "r");
size_t entries = 0;
if (input != NULL)
{
char buffer[40];
while (fgets(buffer, sizeof(buffer), input) != NULL && entries < 100)
{
int res = sscanf(buffer, "%d %d", &values[entries][0], &values[entries][1]);
if (res <= 1 || res == EOF)
{
// Read the last line with only one number, or an error happened
values[entries][0] = 0;
values[entries][1] = 0;
break;
}
++entries;
}
if (ferror(input))
{
printf("Error reading file\n");
}
fclose(input);
}
// All done, the number of "records" or "entries" is in the variable entries
// Example code: print the values
for (size_t i = 0; i < entries; ++i)
printf("Line %d: %d %d\n", i + 1, values[i][0], values[i][1]);
return 0;
}

Read numbers from text file and use them as input

I have this text:
0 0 0 0 0 1
0 0 0 0 1 1
0 0 0 1 0 1
0 0 0 1 1 1
I want to read the first 5 numbers from each line and then use them as inputs in a function.
I'm new to c and have only accomplished this code that doesn't do much, if anything really.
int v,o;
FILE *mydata;
if ((mydata = fopen("testinputs.txt", "rt"))==NULL)
{
printf ("file can't be opened'\n");
exit(1);}
fclose(mydata);
How do i complete it?
Thank you.
Well, assuming your file is called "input.txt", then this is all you need to do:
#include <stdio.h>
#include <stdlib.h>
#define LINE_LEN 100
int main ( void )
{
char line[LINE_LEN];
int sum, i, read_cnt, numbers[5];//sum and i are there for my example usage
FILE *in = fopen("input.txt", "r");//open file
if (in == NULL)
{
fprintf(stderr, "File could not be opened\n");
exit( EXIT_FAILURE);
}
while((fgets(line, LINE_LEN, in)) != NULL)
{//read the line
//scan 5 numbers, sscanf returns the number of values it managed to extract
read_cnt = sscanf(
line,
"%d %d %d %d %d",
&numbers[0],
&numbers[1],
&numbers[2],
&numbers[3],
&numbers[4]
);
//check to see if we got all 5 ints
if (read_cnt != 5)
printf("Warning: only read %d numbers\n", read_cnt);//whoops
//just an example, let's add them all up
for (sum= i=0;i<read_cnt;++i)
sum += numbers[i];
printf("Sum of numbers was: %d\n", sum);
}
return EXIT_SUCCESS;
}
With this input.txt file:
1 2 3 4 5
2 2 2 2 2
1 23 2 3 4
12 23
This gives us the following output:
Sum of numbers was: 15
Sum of numbers was: 10
Sum of numbers was: 33
Warning: only read 2 numbers
Sum of numbers was: 35
That should be more than enough to get you started
Here is a small code to read character by character and store only the wanted numbers:
C Code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int c; // Character read from the file
int cpt; // Counter (to get only 5 numbers per line)
int i,j; // Array indexes
int data[4][5]; // 2D integer array to store the data
FILE *f; // File
if ((f = fopen("file.txt", "r")) == NULL) // Open the file in "read" mode
{
printf ("file can't be opened'\n");
exit(255);
}
// Counter and indexes initialization
cpt=0;
i=0;
j=0;
// Read the file till the EOF (end of file)
while ((c = fgetc(f)) != EOF)
{
// If 5 numbers read, go to new line, first index in the data array and to the next line in the file
if(cpt==5)
{
i++;
cpt=0;
j=0;
while(c != '\n' && c != EOF)
c=fgetc(f);
}
// If a number is read, store it at the right place in the array
if(c>='0'&&c<='9')
{
// Convert character to integer (see ascii table)
data[i][j] = c-'0';
j++;
cpt++;
}
}
// Display the array
for(i=0;i<4;i++)
{
for(j=0;j<5;j++)
printf("%d ", data[i][j]);
printf("\n");
}
fclose(f);
}
And here is the output:
0 0 0 0 0
0 0 0 0 1
0 0 0 1 0
0 0 0 1 1
Now you can use your 2D array, for example if you want a variable a to have the 2nd line, 3rd number, you'd do : a = data[1][2]
Don't forget arrays start at index 0
Hope this helps...
It might help you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
FILE *datafile;
int main()
{
char line[100],*ch;
int count;
datafile = fopen ( "my.txt", "r");
while ( fgets(line , sizeof line , datafile) != NULL )//fgets reads line by line
{
count = 0;
ch = strtok ( line , " ");
while ( count < 5 && ch != NULL )
{
printf("%d ",*ch - 48 );//*ch gives ascii value
//pass to any function
count++;
ch = strtok ( NULL, " ");
}
}
return 0;
}
The above program passes integer by integer.

handling trailing \n when using feof()

I have written a small program which takes input of a file such as:
13,22,13,14,31,22, 3, 1,12,10
11, 4,23, 7, 5, 1, 9,33,11,10
40,19,17,23, 2,43,35,21, 4,34
30,25,16,12,11, 9,87,45, 3, 1
1,2,3,4,5,6,7,8,9,10
and outputs the largest sum of numbers on each line that is less than 50.
However if the inputted file has a trailing newline character the loop runs one too many times and hence another line is added to the array with random data. So I'm looking for a better way to do this comparison to avoid this issue. I'm also assuming all lines have 10 integers on at the moment as i cannot think of a better way to do the end of line loop comparison.
#include <stdio.h>
#include <stdlib.h>
void readLineData(int lineNo, int val[][10], FILE *fp);
int findSum(int lineNo, int val[][10], FILE *fp);
int main(int argc, char *argv[]) {
FILE *fp;
int val[5][10];
// Open file.
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file ");
exit(EXIT_FAILURE);
}
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
}
fclose(fp);
return EXIT_SUCCESS;
}
void readLineData(int lineNo, int val[][10], FILE *fp) {
char c;
for (int i = 0; i < 10; i++) // assuming line contains 10 integers
{
fscanf(fp, "%d,", &val[lineNo][i]);
}
}
int findSum(int lineNo, int val[][10], FILE *fp) {
int highVal = 0;
int value1 = 0;
int value2 = 0;
for(int i = 0; i < 10; i++) //each letter
{
for(int j = 0; j < 10; j++)// every other letter
{
if((val[lineNo][i] + val[lineNo][j]) > highVal && i != j && (val[lineNo][i] + val[lineNo][j]) <= 50)
{
highVal = val[lineNo][i] + val[lineNo][j];
value1 = val[lineNo][i];
value2 = val[lineNo][j];
}
}
}
printf("Line %d: largest pair is %d and %d, with a total of: ", lineNo+1, value1, value2);
return highVal;
}
any help with those loop comparisons and general notation tips is most welcome.
Thanks
The posted code does not distinguish between two lines that have five integers and (the expected) one line that has 10 integers. Suggest reading in a line at a time, using fgets() and then using sscanf() on the read line to ensure that all the read integers belong to the same line.
Check the return value of input operations. For example, sscanf() (and fscanf()) return the number of assignments made. Only process lines that have the expected 10 integers, which would detect invalid lines including the trailing empty line.
For example:
/* Returns 1 on success and 0 on failure. */
int readLineData(int lineNo, int val[][10], FILE *fp)
{
char line[1024]; /* Arbitrarily large. */
if (fgets(line, sizeof(line), fp))
{
/* %n records position where processing ended. */
int pos;
const int result = sscanf(line,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
&val[lineNo][0],
&val[lineNo][1],
&val[lineNo][2],
&val[lineNo][3],
&val[lineNo][4],
&val[lineNo][5],
&val[lineNo][6],
&val[lineNo][7],
&val[lineNo][8],
&val[lineNo][9],
&pos);
/* 10 integers and full line processed,
except if new-line character present. */
return 10 == result &&
(pos == strlen(line) ||
(pos + 1 == strlen(line) && '\n' == line[pos]));
}
return 0;
}
You could simply consume the newline character yourself:
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
fscanf(fp, "%*c"); // read a character without storing it in a variable
}
Note that there are undoubtedly better ways that involve reading an entire line at once and simply examining its contents; but this is the easiest way that will fit with what you already have.
you could check if fscanf fails in your readLineData function:
int readLineData(int lineNo, int val[][10], FILE *fp) {
for (int i = 0; i < 10; i++) {// assuming line contains 10 integers
if (fscanf(fp, "%d,", &val[lineNo][i]) != 1) {
return 1;
}
}
return 0;
}

Resources