I have the following text file
0 0 0 debut
1 120 0 permis exploitation
2 180 1 1 piste 6km
3 3 1 2 installation sondeuses
4 30 1 2 batiments provisoires
5 60 1 2 groudronnage piste
6 90 1 4 adduction eau
7 240 2 3 4 campagne sondage
8 180 3 5 6 7 forage 3 puits
9 240 3 5 6 7 construction bureaux logements
10 30 2 8 9 transport installation matériel
11 360 2 8 9 traçage du fond
12 240 2 8 9 construction laverie
13 0 3 10 11 12 fin des travaux
Each line is the representation of a task and is described as followed: the first number is and ID, the second is the duration, the third is the number of previous tasks that are required, and all the numbers afterward are the IDs of the required tasks. Finaly the string in the end is the title of the string.
I'm trying to fill an array of those struct by reading this file. Here is the struct:
typedef struct{
int id;
int duration;
int nbPrev; /* number of required previous tasks */
int prev[NMAXPREV]; /*array of required previous tasks*/
char title[LGMAX];
}Task ;
Here is my code to read the file
int readTasksFile(char* file_name, Task t[])
{
FILE* f;
char line[256] = {'\0'};
int i = 0;
char c[1] = {0};
if((f = fopen(file_name, "r")) == NULL)
{
perror("The file couldn't be opened");
exit(EXIT_FAILURE);
}
while (fgets(line, 256, f) != EOF)
{
sscanf_s(line, "&d &d &d", &(t[i].id), &(t[i].duration), &(t[i].nbPrev));
i++;
}
fclose(f);
return 0;
}
How can I read all the previous tasks number in a line considering it is variable and still be able to read the title afterward ?
How can I read all the previous tasks number in a line considering it is variable and still be able to read the title afterward ?
The 3rd int should be the number of following ints.
Use "%n" to record scan offset.
After reading the .prev[], copy the rest of the line to .title.
Add error checking. This is very important, especially for complex input.
// Untested code to get OP started
// while (fgets(line, 256, f) != EOF) Comparing against EOF is incorrect
while (fgets(line, sizeof line, f)) {
int offset = 0;
// Use %d, not &d
if (sscanf(line, "%d %d %d %n",
&t[i].id, &t[i].duration, &t[i].nbPrev, &offset) != 3) {
// Handle bad input, for now, exit loop
break;
}
if (t[i].nbPrev < 0 || t[i].nbPrev > NMAXPREV) {
// Handle bad input, for now, exit loop
break;
}
char *p = line + offset;
int prev;
// Populate t[i].prev[]
for (prev = 0; prev < t[i].nbPrev; prev++) {
if (sscanf(p, "%d %n", &t[i].prev[prev], &offset) != 1) {
break;
}
p += offset;
}
if (prev != t[i].nbPrev) {
// Handle bad input, for now, exit loop
break;
}
// remaining text
int len = strlen(p);
if (len > 0 && p[len-1] == '\n') p[--len] = '\0'; // consume potential trailing \n
if (len >= LGMAX) {
// Handle bad input, for now, exit loop
break;
}
strcpy(t[i].title, p);
i++;
}
return i; // Let caller know of successful lines parsed.
Advanced: robust code would use strtol() instead of "%d" and sscanf().
readTasksFile() should also pass in the max number of Task t[] that can be read.
You could also scan by line and assign the two first numbers to id and duration, then do an int analysis and add the rest of the elements to nbPrev until you encounter a letter.
I don't know if this would be the best way to do it, but it's how I would do it.
Why don't you create also a list each time you register in struct nbPrev?
Like, instead of nbPrev being of type int, make it of type list?
Related
I have a text file that contains:
1 1 1
1 2 2
1 3 2
1 7 5
1 8 4
1 9 4
1 10 2
...
and this is my function:
void addRatings()
{
int n,m,l;
int a[50][100];
MovieR = fopen("d://ratings.txt","r");
l = LineNum(MovieR);
MovieR = fopen("d://ratings.txt","r");
for(int i=0;i<l;i++)
{
fscanf(MovieR,"%[^\t]\t%[^\t]\t%[^\t]\n",&n,&m,&a[n][m]);
}
}
Now I want to get the first and second column for n and m
then I want to give third column to the a[n][m].
How can I do that?
You need to read the third value into a temporary variable, and then store that value into the array if and only if the following conditions are met:
fscanf returned 3, meaning that it actually found three numbers
the value for n is between 0 and 49 inclusive
the value for m is between 0 and 99 inclusive
And the code doesn't need to count the number of lines (using LineNum()). The loop should end when fscanf runs out of numbers to read, i.e. returns something other than 3.
The resulting code looks something like this:
void addRatings(void)
{
int a[50][100] = {{0}}; // initialize all ratings to 0
FILE *MovieR = fopen("d://ratings.txt", "r");
if (MovieR != NULL)
{
int n, m, rating;
while (fscanf(MovieR, "%d%d%d", &n, &m, &rating) == 3) // loop until end-of-file
{
if (n < 0 || n > 49 || m < 0 || m > 99) // check for valid indexes
break;
a[n][m] = rating;
}
fclose(MovieR);
}
}
Problem: Write a program that reads all integers that are in the range
of 0 to 100, inclusive from an input file named: a.txt and counts how
many occurrences of each are in the file. After all input has been
processed, display all the values with the number of occurrences that
were in are in the input file.
Note: The program ignores any number less than 0 or greater than 100.
Note: Do not display zero if a number is not in the file. Hints: An
array of size 101 is good enough. A number in the file plays the role
of an index.
For example: Suppose the content of the file: a.txt is as follows:
99 2 99
3
-12 80 12 33
3 99 100 1234 84
The display output is:
2 has occurred: 1 times,
3 has occurred: 2 times,
12 has occurred: 1 times,
33 has occurred: 1 times,
80 has occurred: 1 times,
84 has occurred: 1 times,
99 has occurred: 3 times,
100 has occurred: 1 times
Here is the code that I have right now:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *inFile;
int count = 1, num[101];
inFile = fopen("a.txt", "r");
for(int i = 1; i <= 100; i++) {
fscanf(inFile, "%d", &num[i]);
}
for(int i = 1; i <= 100; i++){
if(num[i] == i) {
printf("%i has occurred: %d times\n", i, count);
count++;
}
}
fclose(inFile);
}
Output:
2 has occured: 1 times
Hello, I'm trying to do this assignment for my C Programming class due Sunday at midnight, but I'm having trouble trying to print all of the numbers from the array with their occurrences. In my code, I first declared int count to increase the number of occurrences if the number is found more than once in the text file and created an array size of 101. Then, I used a for loop to read the text file and store all the numbers from 1-100 into the array. The second for loop, followed by an if statement is to compare the numbers from the array. Even though this is a test program, we are supposed to be able to do this with all data values. Hope this is a good enough explanation, thank you.
You are close.
Instead of reading each value into num, You want to use your num array to keep the count of each number seen in the file.
int main() {
FILE* inFile;
int value = 0;
int result = 0;
int num[101] = { 0 }; // zero-init this array
inFile = fopen("a.txt", "r");
if (inFile == NULL) {
printf("unable to open file\n");
return -1;
}
result = fscanf(inFile, "%d", &value);
while (result == 1) {
printf("Just read: %d\n", value);
if ((value >= 0) && (value <= 100)) {
num[value] = num[value] + 1; // num[value]++
}
result = fscanf(inFile, "%d", &value);
}
for (int i = 0; i <= 100; i++) {
if (num[i] > 0) {
printf("%i has occurred: %d times\n", i, num[i]);
}
}
fclose(inFile);
}
In addition to the good answer by #selbie, from my answer to your earlier question How do I get the counter to work..., you can apply the same principals to filling a Frequency Array here. In this case you simply use n as an index instead of a counter.
For example with your index n and your array num declared (and initialized all zero), you would simply read all integers in the file and check if the value n was between 0 <= n <= 100 and if so , update the value at the index n in your num array by one, e.g. num[n]++;. You could do it like:
int n = 0; /* index */
int num[NELEM] = {0}; /* array */
...
while (fscanf(myFile, "%d", &n) == 1) /* read each int */
if (0 <= n && n <= 100) /* if 0 <= n <= 100 */
num[n]++; /* increment value at index */
Then for your output, you just handle your special check on num[0] to determine whether to output that index, and then loop from 1-NELEM outputting the frequency of occurrence of each value, e.g.
if (num[0]) /* check if 0 found, output if so */
printf ("num[%3d] occurred %3d times\n", 0, num[0]);
for (int i = 1; i < NELEM; i++) /* output counts for 1-100 */
printf ("num[%3d] occurred %3d times\n", i, num[i]);
The complete example could be:
#include <stdio.h>
#define NELEM 101 /* if you need a constant, #define one (or more) */
int main(int argc, char **argv) {
int n = 0; /* index */
int num[NELEM] = {0}; /* array */
/* read filename from 1st argument (stdin by default) */
FILE *myFile = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!myFile) { /* validate myfile is open for reading */
perror ("fopen-myfile");
return 1;
}
while (fscanf(myFile, "%d", &n) == 1) /* read each int */
if (0 <= n && n <= 100) /* if 0 <= n <= 100 */
num[n]++; /* increment value at index */
if (myFile != stdin) /* close file if not stdin */
fclose (myFile);
if (num[0]) /* check if 0 found, output if so */
printf ("num[%3d] occurred %3d times\n", 0, num[0]);
for (int i = 1; i < NELEM; i++) /* output counts for 1-100 */
printf ("num[%3d] occurred %3d times\n", i, num[i]);
}
Example Use/Output
With 500 random integers in a file, you would get output similar to:
$ ./bin/fscanffreq dat/500_rand_0-100.txt
num[ 0] occurred 3 times
num[ 1] occurred 8 times
num[ 2] occurred 7 times
num[ 3] occurred 2 times
num[ 4] occurred 1 times
num[ 5] occurred 4 times
num[ 6] occurred 3 times
num[ 7] occurred 5 times
num[ 8] occurred 6 times
num[ 9] occurred 4 times
num[ 10] occurred 6 times
...
num[ 95] occurred 6 times
num[ 96] occurred 4 times
num[ 97] occurred 6 times
num[ 98] occurred 2 times
num[ 99] occurred 5 times
num[100] occurred 6 times
(note: if num[0] was 0, it would not be displayed)
Look things over and let me know if you have further questions.
samplegame.txt(actual_file)
6
2 3 3
11 2
18 1
10 3
22 14
30 19
8 16
12 24
20 33
i want to read data .txt file into my C program.for each line separate them and store them in the variable,so i can use in further step.i'm trying to use
FILE* file = fopen (argv[1], "r");
int i = 0;
fscanf (file, "%d", &i);
while (!feof (file))
{
//printf ("%d ", i);
fscanf (file, "%d", &i);
}
fclose (file);
but i got all the number in one line and can't figure out how to separate each group like
int board_size = 6 << 1st line
int minion_box_size = 2; << 2nd line
int trap_size = 3;
int trampoline_size = 3;
int minion_box[minion_box_size] = {11,18}; << 3rd to N line
int minion_walk[minion_box_size] = {2,1};
int trap_position[trap_size] = {10,22,30}; << N+1 to M line
int trap_end[minion_box_size] = {3,14,19};
int trampoline_position[trampoline_size] = {8,12,20}; << M+1 to k line
int trampoline_jump[trampoline_size] = {16,24,33};
Anyone has a suggestion ?
samplegame.txt(explained)
______Board_________
6 // size of game board
_____size of each item_________
2 3 3 // first number in this line is Minion_box,which means there is 2 Minion_box
// Second number is trap_holes,which means there is 3 traps
// third number is trampoline,which means there is 3 trampolines
_____Minion_Box_______
// first number : where the minion_box are
// Second number : how many step that the minion can walk
11 2 // the box is in 11th block , minion has aiblity to walk 2 step
18 1 // the box is in 18th block , minion has ability to walk 1 step
______Traps__________
// first number : where the traps are
// Second number : the block you gonna be,after stepping on the trap.
10 3 // there is a trap hole in the 10th block,step on it and you will fall down 3rd block
22 14 // a trap hole in the 22th block,fall down to 14th block
30 19 // a trap hole in the 30th block,fall down to 19th block
____trampoline_______
// first number : where the trampoline are
// Second number : the block you gonna be,after stepping on the trampoline.
8 16 // there is a trampoline in 8th block,if you step on it you will jump to 16th block
12 24 // trampoline in 12th block,jump to 24th block
20 33 // trampoline in 20th block,jump to 33th block
Sorry for bad english and really long post,since i'm not good in english so i'm trying to show the example as much as possible :(
If you want to read a file line after line, better use fgets() and sscanf().
char buffer[BUFFER_SIZE]; // with a #define BUFFER_SIZE 1024 or whatever sooner in the code
int first_value, second_value;
if (fgets(buffer, BUFFER_SIZE, f) == NULL)
{
if ferror(f)
{
perror("");
}
exit(1);
}
if (sscanf(buffer, "%d %d", &first_value, &second_value) != 2)
{
fprintf(stderr, "missing value\n");
exit(1);
}
I have to read a file like this:
0 -> 1:50 2:30 3:10
1 ->
2 -> 0:10 3:20
3 -> 1:20 2:10 3:30
Here's my code:
graphs = fopen(argv[2],"r");
if(graphs==NULL){
printf("File hostgraphs not found\n");
exit(EXIT_FAILURE);
}
while((err=fscanf(graphs,"%d ->",&num))==1){
row=num;
while((err1=fscanf(graphs," %d:%d ",&column,&visits))==2){
hostgraphs[row*n+column]=visits;
}
if(err1!=2)
break;
if(err==0){
printf("Hostgraph out of bounds\n");
exit(EXIT_FAILURE);
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%d ", hostgraphs[i*n+j]);
}
printf("\n");
}
It gives me the following result:
0 50 30 10
0 0 0 0
0 0 0 0
0 0 0 0
The expected output must be:
0 50 30 10
0 0 0 0
10 0 0 20
0 20 10 30
Can anyone help me please?
You can do this by reading the file, one line at a time, using getline, and then applying the same logic, as you are doing, on each line separately.
In the following code, I first get a single line from the file in buffer using getline method. Then I process that line as a FILE pointer fbuffer using fmemopen method, which is used to read a string like a file:
graphs = fopen(argv[2],"r");
if(graphs==NULL)
{
printf("File hostgraphs not found\n");
exit(EXIT_FAILURE);
}
char *buffer = NULL;
size_t len = 0;
while(getline(&buffer, &len, graphs) != -1)
{
FILE * fbuffer = fmemopen(buffer, len, "r");
while((err=fscanf(fbuffer,"%d -> ",&num))==1)
{
row=num;
while((err1=fscanf(fbuffer," %d:%d ",&column,&visits))==2)
{
hostgraphs[row*n+column]=visits;
}
if(err1!=2)
{
break;
}
if(err==0)
{
printf("Hostgraph out of bounds\n");
exit(EXIT_FAILURE);
}
}
free(buffer);
buffer = NULL;
len = 0;
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("%d ", hostgraphs[i*n+j]);
}
printf("\n");
}
Note: I have just added code to make your existing code work, without making any changes to your code.
The fix is simple: remove the trailing space in the fscanf format string in
fscanf(graphs," %d:%d ",&column,&visits)
It should be simplified as
fscanf(graphs,"%d:%d", &column, &visits)
fscanf ignores the newline then after read first row, it moves to next row and read 5 and results 1 in err1. That is the root-cause. You can add fseek to move back and start new sequence as bellow code-snip or simply change the algorithm to another effective one.
graphs = fopen(argv[2],"r");
if (!graphs) {
printf("File hostgraphs not found<%s>\n", argv[1]);
exit(EXIT_FAILURE);
}
while((err = fscanf(graphs, "%d ->", &num)) == 1) {
pos = ftell(graphs); // save position
while((err1 = fscanf(graphs, " %d:%d", &column, &visits)) == 2 ) {
hostgraphs[num * n + column] = visits;
pos = ftell(graphs); // save position
}
// seek back to previous one and start new sequence
fseek ( graphs , pos, SEEK_SET );
}
for(i = 0; i< n; i++){
for(j = 0; j < n; j++){
printf("%d ", hostgraphs[i * n + j]);
}
printf("\n");
}
You were close, but you needed a way of locating each '\n' without reading the next row value from the file. That is very difficult to do with fscanf where you have varying number of elements in each row in your input file.
Another approach is to use fgets to read the entire line, and then separate the initial "row -> " prefix from the data values. If you move the values into a separate values buffer (say vbuf), you can then repeatedly loop through the buffer by finding the space, advancing to the next digit and then using sscanf to split the column and visits.
(you actually don't even need to split the values in vbuf, you can simply use a pointer to advance past the "row -> " text working with the entire line.)
The following example puts those pieces together and parses the values into the correct positions in hostgraphs. Look it over and let me know if you have questions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { COLS = 4, MAXH = 16, MAXC = 64 };
int main (int argc, char **argv) {
char buf[MAXC] = "", vbuf[MAXC] = "";
char *p = NULL, *rfmt = "%d -> %[^\n]";
int row, column, visits, hostgraphs[MAXH] = {0};
size_t i, j, n = 0;
FILE *graphs = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!graphs) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, graphs))
{
*vbuf = 0; /* initialize vbuf, split %d:%d pars into vbuf */
if (sscanf (buf, rfmt, &row, vbuf) < 1)
break;
if (!*vbuf) { /* check vbuf contians values */
n++;
continue;
}
/* read 1st pair */
if (sscanf (vbuf, "%d:%d", &column, &visits) != 2) {
fprintf (stderr, "error: invalid line format\n");
exit (EXIT_FAILURE);
}
hostgraphs[row*COLS+column] = visits;
p = vbuf; /* assign p, parse remaining pairs */
while ((p = strchr (p, ' '))) /* find space */
{
while (*p < '0' || '9' < *p) /* find digit */
p++;
if (sscanf (p, "%d:%d", &column, &visits) == 2)
hostgraphs[row*COLS+column] = visits;
}
n++; /* advance row count */
}
for (i = 0; i < n; i++) { /* output values */
printf (" row[%2zu] : ", i);
for(j = 0; j < COLS; j++) {
printf (" %2d", hostgraphs[i * COLS + j]);
}
printf ("\n");
}
if (graphs != stdin)
fclose (graphs);
return 0;
}
Input File
$ cat ../dat/hostgraph.txt
0 -> 1:50 2:30 3:10
1 ->
2 -> 0:10 3:20
3 -> 1:20 2:10 3:30
Output
$ ./bin/hostgraph < ../dat/hostgraph.txt
row[ 0] : 0 50 30 10
row[ 1] : 0 0 0 0
row[ 2] : 10 0 0 20
row[ 3] : 0 20 10 30
I'm trying to extract the content of a file into a matrix but the file may look completely differently.
For exemple all these files should give the same result : a 3x3 matrix containing 1,2,3,4,5,6,7,8,9.
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
1 2 3 4
5
6
7 8
9
1 2 3
$something
$something else
4 5 6
$something else else
7 8 9
Hopefully I know the dimensions of the matrix beforehand as well as the "$" character that indicates that these lines are to be ignored in the current process.
My current algorithm using fscanf works great but It can't work with the "$something" lines.
I figured that I should use the fgets/strtok/sscanf method but there are some issues.
// File* file (already assigned)
char line[32]; //assuming 32 is enough
char* token;
fgets(line,32,file);
token = strtok(line," \t");
for (y=0; y<ySize; y++)
{
for (x=0; x<xSize, x++)
{
if (token[0] == '$') //should use a str function
{
fgets(line,32,file);
token = strtok(line," \t")
x--;
}
else
{
if (we are at the end of the line)
{
fgets(line,32,file);
token = strtok(line," \t")
}
sscanf(token,"%d",&matrix[x][y];
token = strtok(NULL," \t");
}
}
}
Basically I'd like to have some help to write the "if (we are at the end of the line)" condition and some input on my method, is it flawless? Did I correctly thought of the process?
Thank you.
You should use getline instead of fgets to make things easier. The latter is unreliable. The test condition that you are looking for is:
token == NULL;
Check this: "Once the terminating null character of str has been found in a call to strtok, all subsequent calls to this function with a null pointer as the first argument return a null pointer."
You can easily parse without strtok() by using strspn() / strcspn(), and sscanf()s "%n" specifier. Also: there was a ',' in the original code where a ';' should have been.
#include <stdio.h>
#include <string.h>
#define XSIZE 3
#define YSIZE 3
int matrix[XSIZE][YSIZE];
int main(void)
{
char line[200];
int pos,eat,xx,yy, rc;
xx = yy =0;
while ( fgets(line, sizeof line, stdin) ) {
if (line[0] == '$') continue;
for(pos=0; line[pos]; pos += eat) {
pos += strspn(line+pos, " \t\n");
rc =sscanf(line+pos, "%d%n", &matrix[xx][yy], &eat);
if (rc < 1) break;
if (++xx >= XSIZE ) {xx = 0; if(++yy >= YSIZE) goto done; }
}
}
done:
/* show it to the world ... */
for (yy = 0; yy < YSIZE; yy++) {
for (xx = 0; xx < XSIZE; xx++) {
fprintf (stdout, " %d", matrix[xx][yy] );
}
fprintf (stdout, "\n" );
}
return 0;
}