0

I'm trying to create phone book which has five function in c. I have formed just first function which takes and saves in file people's knowledge. However, I cannot succeed the second function which search just a person's (Not all people) knowledge from file.

To run this function (""display() function"") I want to a name from user to search and to display that name's knowledge on the screen. I wrote something but it didn't work. The problem is display() function. How can I read just one line and print it on the screen? Thanks in advance.

#include <stdio.h>
#include <stdlib.h>     // "stdlib" library contains of exit() and malloc function                        
#include <Windows.h>   // "Windows" library contains of Sleep() function
#include <string.h>   // "string" library contains of strcmp() function

struct personKnowledge
{
    char number[16];
    char name[16];
    char surname[16];
};

void newRecord();
void display();
void deletE();
void add();
void update();

FILE *ptrFILE;

int main()
{
    int choice;
    printf("\n\t\t *-* Phone Book Program *-*");
    do
    {
        printf("\n\n\t\t 1) New record");   // The options are being presented to user
        printf("\n\n\t\t 2) Display person knowledge");
        printf("\n\n\t\t 3) Delete someone");
        printf("\n\n\t\t 4) Add new person");
        printf("\n\n\t\t 5) Update person knowledge");
        printf("\n\n\t\t 6) Exit");
        printf("\n\n\nEnter your choice: ");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
        {
            newRecord();
            break;
        }
        case 2:
        {
            display();
            break;
        }
        case 3:
        {
            break;
        }
        case 4:
        {   
            break;
        }
        case 5:
        {
            break;
        }
        case 6:
        {
            printf("\nWorking has been completed.\n");
            exit(0);
            break;
        }
        default:
        {
            printf("\nWrong entry! The program has been terminated.\n");
        }
        }   
    } while (choice >=1 && choice <=6 );
    return 0;
}

void newRecord()
{
    system("cls");   // Screen is being cleaned
    if ((ptrFILE = fopen("Phone Book.txt", "w")) == NULL)
    {
        printf("The file couldn't open\n");
    }
    else
    {          
        struct personKnowledge *p;   // p means person
        p = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));   // Memory is being allocated
        fflush(stdin);
        printf("\n\nDetermine person name: ");   // User is entering the person's knowledge and they are being saved in file
        gets(p->name);
        printf("Determine %s's surname: ", p->name);
        gets(p->surname);
        printf("Determine %s's number: ", p->name);
        gets(p->number);
        fprintf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
        fprintf(ptrFILE, "--------\t\t   ----------------\t\t\t---------------------\n");
        fprintf(ptrFILE, "\n%s%33s%38s\n", p->name, p->surname, p->number);
        fclose(ptrFILE);
        free(p);
        printf("Please wait, information is saving to file..\n");
        Sleep(1000);
        printf("*-* Saving operation has been completed. *-*");
    }
    fclose(ptrFILE);
}

void display()
{
    struct personKnowledge *s;   // s means searching
    char name[16];
    if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
    {
        printf("The file couldn't open\n");
    }
    else
    {
        fseek(ptrFILE, 0L, SEEK_SET);
        printf("Express name which you search: ");
        gets(s->name);
        while (!feof == NULL)
        {
            fscanf(ptrFILE,"%s", &name);
            if (strcmp(s->name, name) == 0)
            {
                printf("qawsdsdf");
            }
        }
    }
    fclose(ptrFILE);
}
NoWeDoR
  • 49
  • 5
  • 1
    You'll probably need `fopen("Phone Book.txt", "a")` if you want to append a record to an existing file. Note `"a"` instead of `"w"` which will destroy the existing file. – Weather Vane Jul 01 '15 at 16:11
  • 1
    I see you are using the dreaded `feof()`, please read the man page as your usage will fail, also http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong. Better to use `while (fgets(...) != NULL)` and strip the trailing linefeeds. – Weather Vane Jul 01 '15 at 16:16
  • 2
    `if (s->name == name)` is wrong, it compare pointers. You need `if(strcmp(s>name, name)==0)` to compare the string contents. I suspect I'll find plenty more errors if I look further. – Weather Vane Jul 01 '15 at 16:19
  • and `fclose(ptrFile)` your files please! – ikrabbe Jul 01 '15 at 16:28
  • just a side note, those curly bracers for the switch cases are not necessary and saves you some lines of code! – Dumbo Jul 01 '15 at 16:32
  • I've corrected the mistakes that you said and I edited my codes at topic. Well, how can I read the specific line and print it? Thanks for interest – NoWeDoR Jul 01 '15 at 16:40
  • 1
    Add to display function `s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));` – Nithin Jose Jul 01 '15 at 16:46
  • 1
    remove the duplicate `fclose(ptrFILE);` in `newRecord` – Nithin Jose Jul 01 '15 at 17:00
  • 1) always compile with all warnings enabled, then fix those warnings. 2) function 'gets()' has been removed from the C language, due to its' many problems, use 'fgets()' instead 3) function 'feof()' returns true or false, never NULL and feof() should 'never' be used to control a loop. Suggest using the fscanf() to control the loop 4) when performing an file open or input operations, always check the returned value to assure the operation was successful – user3629249 Jul 01 '15 at 17:05
  • when calling the scanf() (and family of functions) always check the returned value (not the parameter value) to assure the operation was successful. Note 'case' statements are delimited by the 'case' and the next 'case' so wrapping the following statements in braces '{' and '}' just clutters the code and is only ever needed if using an older version of C and some 'auto' variable is to be generated for that case. The 'default' case should also be terminated via a 'break;' statement. – user3629249 Jul 01 '15 at 17:08
  • in function: newRecord(), fclose() is being called even if the file failed to open via the fopen() call. this line: 'if ((ptrFILE = fopen("Phone Book.txt", "w")) == NULL)' truncates the output file every time it is called. suggest the opening mode be "a" so each call to fopen() appends to the file rather than replacing the file – user3629249 Jul 01 '15 at 17:14
  • when calling malloc() (and family of functions) always check (!=NULL) the returned value to assure the operation was successful. in C, do not cast the returned value from malloc() (and family of functions) – user3629249 Jul 01 '15 at 17:15
  • the C standard specifically states that 'fflush( stdin );' is not part of the language (although some implementations allow it) rather use: while( int ch = getchar() && '\n' != ch && EOF != ch ); – user3629249 Jul 01 '15 at 17:17
  • the function 'Sleep()' and 'sleep()' are depreciated. suggest using 'nanosleep()' found in 'time.h' – user3629249 Jul 01 '15 at 17:19
  • always check the returned value from fseek() to assure the operation was successful. in function: 'display()' a call is made to fclose on a file that might not be open. suggest moving the call to fclose to inside the 'else' code block. – user3629249 Jul 01 '15 at 17:23
  • there are lots of other problems in the code, for instance, when a file is first opened, the file pointer will be at the beginning of the file, so an immediate call to fseek() to the first character in the file is a total waste of time and resources. in the display() function, there is a lot more characters than just the name. suggest reading a struct personknowledge number of characters so read the whole struct then compare with the one field. – user3629249 Jul 01 '15 at 17:31
  • 'magic' numbers should not be in the code, They make understanding difficult and maintenance a nightmare. Suggest #defining the 'magic' numbers, similar to '#define MAX_FIRST_NAME_LEN (16)' and then use the #define name when ever referring to the length of the first name field – user3629249 Jul 01 '15 at 17:36
  • this kind of line: 'while (!feof == NULL)' is comparing the address of the feof() function with NULL and only continuing in the loop if the address is NULL. However, the address is NEVER NULL and due to operator precedence, the line would not be evaluated like you seem to expect.. feof() is a function, so, if (and that is a big IF) the feof() function were to be used to control a loop (which it should not be) then the proper line is: 'while( !feof( ptrFILE ) )' – user3629249 Jul 01 '15 at 17:41

3 Answers3

2

In answer to one of your questions, I recommend rewriting this loop in display()

while (!feof == NULL)                   // wrong way to use feof
{
    fscanf(ptrFILE,"%s", &name);        // might overflow the string space
    if (s->name == name)                // wrong way to compare strings
    {
        printf("qawsdsdf");             // missing newline?
    }
}

with this

while (fgets(name, sizeof(name), ptrFILE) != NULL)  // safer way to read to a small buffer
{
    name [ strcspn(name, "\r\n") ] = 0; // remove trailing newline etc
    if (strcmp(s->name, name) == 0)     // compare the strings
    {
        printf("qawsdsdf\n");           // added newline
    }
}

EDIT in any case your posted code does not even compile properly:

while (!feof == NULL)

is rubbish, it should have been

while (!feof(ptrFILE))

although as I said is not the way to use feof anyway. This would not have happened if you had compiler warnings enabled and dealt with them.

Community
  • 1
  • 1
Weather Vane
  • 33,872
  • 7
  • 36
  • 56
0

My solution was to change how the file is formatted

fprintf(ptrFILE, "\n%s%33s%38s", p->name, p->surname, p->number);

Because if you're using a program to retrieve information, there's no need to fill it with a bunch of junk headers every time you write to it. I then edited the display function to be able to retrieve said information.

void display()
{
    struct personKnowledge s;   // s means searching
    char name[16];
    char sname[16];
    char number[16];
    char surname[16];
    if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
    {
        printf("The file couldn't open\n");
    }
    else
    {
        printf("Express name which you search: ");
        scanf("%s", &sname);
        do
        {
            fscanf(ptrFILE,"%s%33s%38s", &name, &surname, &number);
            if (strcmp(sname, name) == 0)
            {
                printf("%s %s %s", name, surname, number);
            }
        }
        while (strcmp(sname, name) != 0);
    }
}

P.S. I'm still new to c myself and I don't think I could give you a good explanation as to why my code works and yours doesn't. But I can say that those headers you were writing to the file every time was a major part of the problem when I was troubleshooting your code.

Ulrick
  • 33
  • 7
0

I think these minor changes will solve your problem

  • Allocate memory for storing personKnowledge s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));
  • Make file pointer reach the starting location of data. A simple trick has been used to achieve this fscanf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n"); fscanf(ptrFILE, "--------\t\t ----------------\t\t\t---------------------\n");
  • Make change in while loop.while (!feof(ptrFILE))
  • Scanning one row of data.fscanf(ptrFILE, "\n%s%33s%38s\n", s->name, s->surname, s->number)
  • Make change in string comparison.if (strcmp(name,s->name) == 0)

The modified display function

    void display(){
      struct personKnowledge *s;   
      s = (struct personKnowledge *)malloc(sizeof(struct personKnowledge));   // Memory is being allocated for s
      fflush(stdin);

      char name[16];
      if ((ptrFILE = fopen("Phone Book.txt", "r")) == NULL)
      {
      printf("The file couldn't open\n");
      }
      else
      {
      fseek(ptrFILE, 0L, SEEK_SET);
      printf("Express name which you search: ");
      scanf("%s",name);     //the name you want to retrieve

      fscanf(ptrFILE, "Name\t\t\t\tSurname\t\t\t\t\tNumber\n");
      fscanf(ptrFILE, "--------\t\t   ----------------\t\t\t---------------------\n");   //when we read the file for first time we need to start from the first location of person data, this is a trick to make ptrFILE reach there
      fflush(stdin);

      while (!feof(ptrFILE))
      {
      fscanf(ptrFILE, "\n%s%33s%38s\n", s->name, s->surname, s->number);//same format as fprintf used in newRecord
        if (strcmp(name,s->name) == 0)   //comparison
        {
            printf("qawsdsdf");
        }
      }}fclose(ptrFILE);}
Nithin Jose
  • 1,029
  • 4
  • 16
  • 31
  • At first, this method had occured to me but I wanted to write a different way. I see that is difficult, and turn back this writing. Anyway, Thanks for all of your comments. – NoWeDoR Jul 03 '15 at 08:07