1

I want to read from a text file and show some output

Input file format:

0 0 3         
0 1 2         
1 3 4         
2 1 4         
3 2 3         
3 1 2         
4 3 4      

1st digit of each line indicates a particular day (day 0 to 4) and the second and the 3rd digit of each line indicates actors who sends message to each other on that day. I have written the following c code to display the participating actor on each day:

My sample code:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define B 5 // number of days
#define A 5 // number of total actors

main()
{
    FILE *fp;
    int end = 0;
    int day1, day, i, j, k1, k2;
    int esin[A][A];
    for (i = 0; i < A; i++)  // initializing array
    {
        for (j = 0; j < A; j++)
        {
            esin[i][j] = 0;
        }
    }
    fp = fopen("test.txt", "r"); // the file contains the input
    if (fp == NULL)
    {
        printf("\nError - Cannot open the designated file\n");
    }

    while (end == 0)
    {
        fscanf(fp, "%d", &day);
        day1 = day; // day1 for comparing
        while (day1 == day)
        {
            if (feof(fp))
            {
                end = 1;
                break;
            }
            fscanf(fp, "%d %d", &k1, &k2);

            esin[k1][k2] = 1;// edge creation
            esin[k2][k1] = 1;// edge creation

            fscanf(fp, "%d", &day);
        }

        printf("\nday: %d", day1); // for printing output of a particular day
        for (i = 0; i < A; i++)
        {
            for (j = 0; j < A; j++)
            {
                if (esin[i][j] == 0)
                    continue;
                else
                    printf("\n%d and %d have an edge", i, j);
            }
        }
        for (i = 0; i < A; i++)
        {
            for (j = 0; j < A; j++)
            {
                esin[i][j] = 0;
            }
        }
    }
}

But I am not getting the actual output. For example, I want to get an output like:

day 0
0 and 3 have an edge
1 and 2 have an edge
day 1
3 and 4 have an edge
day 2
1 and 4 have an edge
day 3
2 and 3 have an edge
1 and 2 have an edge
day 4
3 and 4 have an edge

But I am not getting this. I am getting:

day 0
0 and 3 have an edge
1 and 2 have an edge
day 3
4 and 2 have an edge
day 4
3 and 2 have an edge
day 3
1 and 2 have an edge
day 3
4 and 2 have an edge

Is there anything wrong in the above code? Which correction will I need to make to get the above like output?

3
  • Please do not spam tags your questions Commented Aug 31, 2016 at 17:48
  • 2
    See while (!feof(file)) is always wrong for a discussion of that idiom. Your code will crash if you fail to open the file — you test, but continue as if nothing had gone wrong. You should report errors on standard error, too, not standard output. And, most of all, you should check that the I/O operations worked by checking the fscanf() calls directly. Commented Aug 31, 2016 at 18:12
  • Just a small bit, since you need esin to be all zeroes, you can skip typing the loops and just write int esin[A][A] = {0}; and all the elements of the 2D array will be initialized to zero. You can read more about it here. Commented Aug 31, 2016 at 22:21

4 Answers 4

1

In this line

if(esin[i][j]=0)

you are assigning, but you want to compare:

if(esin[i][j] == 0)
Sign up to request clarification or add additional context in comments.

3 Comments

I just want to print when esin[i][j]=1. that means there is n activity between actor i and j @Alter Mann
You exit from loop in the first iteration if(esin[i][j]=0) continue; because the condition is always true.
That was a typing mistake. But still I am getting wrong output @Alter Mann
1
  1. Change if(esin[i][j]=0) to if(esin[i][j]==0).

  2. If you do:

        esin[k1][k2] = 1;
        esin[k2][k1] = 1;
    

Output will be for day-0:

day: 0 
0 and 3 have an edge 
1 and 2 have an edge 
2 and 1 have an edge
3 and 0 have an edge

Just do esin[k1][k2] = 1; if you want output like:

day: 0 
0 and 3 have an edge 
1 and 2 have an edge 
  1. And another issue is, day is being scanned twice when day is changing (One inside while(day1 == day) loop and another outside this loop). You can try this:
bool first = true; 

while(end==0)
{
    // Only first time we'll read 'day', 
    // later we won't need this fscanf since there is another fscanf for reading day
    if(first)
    {
        fscanf(fp, "%d", &day);    
    }
    day1 = day; //day1 for comparing
    first = false;    

    while(day1 == day)
    {
        if (feof(fp))
        {
            end=1;
            break;
        }

        fscanf(fp, "%d %d", &k1, &k2);
        esin[k1][k2] = 1;//edge creation
        fscanf(fp, "%d", &day);
    }
    ...
}

1 Comment

But I am getting output like this: day 0 0 and 3 have an edge 1 and 2 have an edge day 3 4 and 2 have an edge day 4 3 and 2 have an edge day 3 1 and 2 have an edge day 3 4 and 2 have an edge @Shahid
1

Here you are scanning one date from input and checking against first integer (which is date) for each next line, when day1 != day your inner loop won't execute but you already read that day value. now when you perform fscanf(fp, "%d", &day) on input it will read person id (2nd column) and it totally get messed up.

I would suggest to do one time file scanning and build graph

int a,b;
for (int i=0; i<5; i++)
for (int j=0; j<5; j++) 
     esin[i][j] = -1; // No edge
while (!feof(fp)) {
     fscanf(fp, "%d %d %d", &day, &a, &b);
     esin[a][b] = day;
     esin[b][a] = day;
}

// for each day find person1,person2
for (int i=0; i<5; i++) {
    printf("Day %d:\n", i);
    for (int p=0; p<5; p++) {
        for (int q=0; q<5; q++) {
            if(esin[p][q] == i) {
                printf ("%d and %d have an edge\n", p, q);
            }
        }
    }
}

4 Comments

Any suggestion with while (!feof(fp)) or equivalent in it is sub-optimal at best and incorrect at worst. See while (!feof(file)) is always wrong for a discussion of why.
Thanks for pointing this out. A nice approach would be run infinite loop and check return length of fscanf(fp, "%d %d %d", &day, &a, &b) if it is less than or equal to zero that means buffer has ended and file i/o pointer is at EOF.
That would be better, but the correct test is "did I get the number of values I requested", so in this case, while (fscanf(fp, "%d %d %d", &day, &a, &b) == 3) { …process valid data… }. You could get two integers read and then a letter in the input stops the third being read. You don't want to proceed as if everything was OK. Also, tangentially, note that fscanf() doesn't care about newlines in this. All the numbers could be on a single line, or each number on a line of its own, or there could be blank lines; it will simply read three integers and leave anything else for reading next time.
You really, really, really don't control loops on while (!feof(fp)); it is wrong unless you also put if checks on the I/O operations, and doing that makes the !feof(fp) test superfluous. It is OK to check for feof(fp) after a loop has broken because the loop failed; then you can report an error if it was not at EOF. But that's a different usage altogether.
1

If you are only interested in printing the input in pretty English [in the same order of the input file]

This smallified code will do so :

#include <stdio.h>
#include <stdlib.h>
#define B 5 // number of days
#define A 5 // number of total actors

int main()
{
    int day1=-1, day, k1, k2;

    FILE *fp= fopen("test.txt", "r"); // the file contains the input
    if (fp == NULL)
    {
        printf("\nError - Cannot open the designated file\n");
        return 0;
    }
    
    while(fscanf(fp,"%d%d%d",&day,&k1,&k2)>0)
    {
        if(day1!=day || day1==-1 )
            printf("\nday: %d", day1=day); 
        printf("\n%d and %d have an edge", k1,k2);
    }
    
    return 0;
}

Buttttt if u really want to store the input for each days and then print it in a lexicographical manner [ASCENDING ORDER OF ACTOR NO] then here is ur modified code :

#include <stdio.h>
#include <stdlib.h>
#define B 5 // number of days
#define A 5 // number of total actors

int main()
{
    int day1=-1, day, i, j, k1, k2;
    int esin[A][A]={0};

    FILE *fp= fopen("test.txt", "r"); // the file contains the input
    if (fp == NULL)
    {
        printf("\nError - Cannot open the designated file\n");
        return 0;
    }
    
    while(!feof(fp))
    {
        if( fscanf(fp,"%d%d%d",&day,&k1,&k2)<0  || (day1!=-1 && day1!=day ))
        {
            printf("\nday: %d", day1<0?day:day1); 
            for(i=0;i<A;i++)
                for(j=0;j<A;esin[i][j]=0,j++)
                    if(esin[i][j])
                        printf("\n%d and %d have an edge", i, j);   
            esin[k1][k2]=1;
            day1=day;
        }
        if(day1==-1)
            day1=day;
        esin[k1][k2]=1;
    }
    
    return 0;   
}

Key Points to remember (also mentioned above in comments) :

  1. scanf family (scanf,fscanf,...) returns -1 on reaching of EOF.
  2. scanf family returns the no of successfully scanned variables.
  3. No explicit reset or initialize to zero is required. Member initializer {0} OR the printing nested for loop for(j=0;j<A;esin[i][j]=0,j++)can do so.
  4. -1 is considered as an invalid day.
  5. if(esin[i][j]) means if(esin[i][j]!=0) i.e. actor i messages actor j.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.