Question

I'm exercising with C and file management, I'm able to open a file, write a record on the file, close the file, but I have problem to find an already written record. This is my exercise: (The search in case 2)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main(){
    struct info{
        char name[40];
        char sur[40];
    };
    struct info rec;
    FILE *f1, *f2;
    int sel, ser, res;
    char cmp[40];
    int cont=0;

    f1=fopen("lis.txt","a+");

    do{
        do{
            printf("1> Add account\n");
            printf("2> Search account\n");
            printf("3> Modify account\n");
            printf("4> Exit\n");
            printf("Type your choice -> ");
            scanf("%d", &sel);
            if(sel<1 || sel>4){
                printf("ERROR: The choice isn't allowed\n");
            }
        }while(sel<1 || sel>4);

        getchar();
        switch(sel){
            case 1:
                printf("Insert new account\n");
                printf("Write name: ");
                fgets(rec.name, sizeof(rec.name), stdin);
                printf("Write surname: ");
                fgets(rec.sur, sizeof(rec.sur), stdin);

                fputs(rec.name,f1);
                fputs(rec.sur,f1);
                fprintf(f1,"\n");

                printf("Account added!\n");
                break;
            case 2:
                printf("Search account\n");
                printf("Write surname to search: ");
                fgets(cmp, sizeof(cmp), stdin);
                while(!feof(f1)){
                    if(strcmp(cmp,rec.sur)==0){
                        printf("ENT\n");
                    }
                }
                break;
    //      case 3:
    //          printf("Modify account\n");
    //          //funzione ricerca qua
    //          printf("Account modificato correttamente!\n");
    //          break;
            case 4:
                printf("Closing...\n");
                break;
            default:
                printf("ERROR!\n");
                break;
        }
    }while(sel!=4);
}

The programme isn't finished, so there are plenty of unused things that I'll fix later. It is tested on OpenVMS.

Was it helpful?

Solution

there is always problem on how to use feof(), so please avoid using it...

why not to use feof() for loop exit condition. please here is link.

here is link to a good tutorial, i have combined it with your code and it works like charm...please look into it.

Below is the modified code,

struct info
{
    char name[40];
    char sur[40];
};

int Search_in_File(char *fname, char *str) {
    FILE *fp;
    int line_num = 1;
    int find_result = 0;
    char temp[40];

    if((fp = fopen(fname, "r")) == NULL) {
        return(-1);
    }

    while(fgets(temp, 40, fp) != NULL) {
        if((strstr(temp, str)) != NULL) {
            printf("A match found on line: %d\n", line_num);
            printf("\n%s\n", temp);
            find_result++;
        }
        line_num++;
    }

    if(find_result == 0) {
        printf("\nSorry, couldn't find a match.\n");
    }

    //Close the file if still open.
    if(fp) {
        fclose(fp);
    }
    return(0);
}


int main()
{

    struct info rec;
    FILE *f1; //*f2;
    int sel;// ser, res;
    char cmp[40];
    char fname[10] = "lis.txt";
    int err = -1;
//    int cont=0;


    do{
        do{
            printf("1> Add account\n");
            printf("2> Search account\n");
            printf("3> Modify account\n");
            printf("4> Exit\n");
            printf("Type your choice -> ");
            scanf("%d", &sel);
            if(sel<1 || sel>4){
                printf("ERROR: The choice isn't allowed\n");
            }
        }while(sel<1 || sel>4);

        getchar();
        switch(sel){
            case 1:
                f1=fopen(fname ,"a+");
                if (!f1) 
                {
                    printf("lis.txt, no such file exits\n");
                    return -1;
                }            
                printf("Insert new account\n");
                printf("Write name: ");
                fgets(rec.name, sizeof(rec.name), stdin);
                printf("Write surname: ");
                fgets(rec.sur, sizeof(rec.sur), stdin);

                fprintf(f1,"%s",rec.name);
                fprintf(f1,"%s\n",rec.sur);

                fflush(f1);
                printf("Account added!\n");
                fclose(f1);
                break;
            case 2:
                printf("Search account\n");
                printf("Write surname to search: ");
                fgets(cmp, 40, stdin);
                err = Search_in_File(fname, cmp);
                if(err < 0)
                {
                    return err;
                }
                break;
          case 3:
              printf("Modify account\n");
              break;
            case 4:
                printf("Closing...\n");
                break;
            default:
                printf("ERROR!\n");
                break;
        }
    }while(sel!=4);

    return 0;
}

OTHER TIPS

There are so many things to look after.
1. Files are not closed properly.

You have opened the file at the beginning of the program. and have never closed. Anything you write into a file does not immediately written actually, they are buffered. You need to flush it or close the file. So, before you do any other operation on the file, be sure it is flushed.

2. Records are not read back from file.

You have not read back the records from file. You always searching the current values of rec structure. You need to read each record to the structure before comparing. Also, if you do not read the file, the file pointer never advances, and the control stays in the loop forever.

3. New lines are not handled.

You have additional new lines after each records. You need to handles those while reading back records from the file. gets consumes one newline at the end of the line. So you need to manually handle the additional \n.

Additionally, you need to break from the while loop if you find your record. There is no point staying there unless you expect duplicates.

The following has some modification over your code. This works for me. You may try this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

main(){
    struct info{
        char name[40];
        char sur[40];
    };
    struct info rec;
    FILE *f1, *f2;
    int sel, ser, res;
    char cmp[40];
    char dummy;
    int cont=0;

    do{
        do{
            printf("1> Add account\n");
            printf("2> Search account\n");
            printf("3> Modify account\n");
            printf("4> Exit\n");
            printf("Type your choice -> ");
            scanf("%d", &sel);
            if(sel<1 || sel>4){
                printf("ERROR: The choice isn't allowed\n");
            }
        }while(sel<1 || sel>4);

        getchar();
        switch(sel){
            case 1:
                printf("Insert new account\n");
                printf("Write name: ");
                fgets(rec.name, sizeof(rec.name), stdin);
                printf("Write surname: ");
                fgets(rec.sur, sizeof(rec.sur), stdin);
                f1=fopen("lis.txt","a+"); //<- open file for writing
                fputs(rec.name,f1);
                fputs(rec.sur,f1);
                fprintf(f1,"\n");
                fclose(f1); // close the file. this will flush the buffer.
                printf("Account added!\n");
                break;
            case 2:
                printf("Search account\n");
                printf("Write surname to search: ");
                fgets(cmp, sizeof(cmp), stdin);
                f1=fopen("lis.txt","r"); //<- open the file for reading
                while(!feof(f1)){
                      fgets(rec.name,sizeof(rec.name),f1); //<- read both the data. this will update the file pointer.
                      fgets(rec.sur,sizeof(rec.sur),f1);
                      fscanf(f1,"%c",&dummy); //<- this handles the additional newline
                    if(strcmp(cmp,rec.sur)==0){
                        printf("RECORD FOUND::\nName:%sSurname:%s\n\n",rec.name,rec.sur);
                        break; //<- break if record is found
                    }
                }
                fclose(f1); //<- close the file after you are done.
                break;
    //      case 3:
    //          printf("Modify account\n");
    //          //funzione ricerca qua
    //          printf("Account modificato correttamente!\n");
    //          break;
            case 4:
                printf("Closing...\n");
                break;
            default:
                printf("ERROR!\n");
                break;
        }
    }while(sel!=4);
}

NOTE: As we are using feof() to exit the loop, we have to read the EOF to fulfil the exit condition. Hence in this code the loop continues one more time after the last record where EOF is read from the file. This is not a problem unless you are trying to print all the records. In that case use a different exit condition.

Let me understand your question first,

you mean you can't find a record that is entered previously.

Lets say that the code at this part:

 printf("Search account\n");
 printf("Write surname to search: ");

 fgets(cmp, sizeof(cmp), stdin);
      while(!feof(f1)){
          if(strcmp(cmp,rec.sur)==0){
              printf("ENT\n");
          }
      }
      break;

does the reading of the file, then....

if you put the code this way:

open the file in case 2 in read mode as a+ will not work if you try to read a file

f1 = fopen("lis.txt", "r");

if (!f1) {
    printf("lis.txt, no such file exits\n");
    return -1;
}

while (feof(f1)) {
    fgets(str, len, f1);
    if (strcmp(str, sur) == 0) {
        /// Do what ever you want, printing the record e.t.c..
    }
}

Hope this helps, :)

The problem begins with the format in which you are writing the file. You could either write the whole struct info for each record or write each field on a line. In the first case, the file would be called "binary"; the second case "text". It seems like you would prefer a text file format.

To write a field on a line, change fputs(rec.name,f1) to fprintf(f1,"%s\n",rec.name), similarly for the other field. Now, a record consists for a fixed number of lines in a specific sequence--specifically, a line for name and a line for sur. You can then read a record with two calls to fgets.

If I read the code correctly then you are trying to search for records after writing them to to file without closing the file. If you want to do this you need to call rewind or fseek to go to the beginning.

Keep in mind that you either need to store you file position before doing this (ftell) or to close and open in append more before adding more records.

As John points out above, reading might not work at all in +a mode either. Best you close the file after each case and open it in the correct mode.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top