0

Hi guys i have a project due to friday where everything works except this one funktion. i have a txt file in which i wanted to read until an ID of my struct comes up. it should then scan my new entrys for this struct and write it over the old struct. Has anyone got an idea why this code isnt working properly? It just writes in other structures and leaves the one i wanted it to write in untouched.

Thats the struct and the code of function:

struct Medicine{
int quantity;
float price;
char ExpDate[15];
char Company[20];
char Supplier[30];
char MediName[20];
char info[1000];
char MediID [30];


void editmed(){
FILE *pt;
int flag=0;
struct Medicine m,mt;
char ID[30];
pt=fopen("mlist.txt","rb+");
if(pt==NULL){
    printf("file opening error");
    getch();
    medicine();
}
else{
    system("cls");
    printf("\nEnter Medicine ID to modify:\n");
    scanf("%s",ID);
    fflush(stdin);
    while(fread(&m,sizeof(struct Medicine),1,pt)==1){
        if(strcmp(ID,m.MediID)==0){
            printf("Enter Medicine ID (only numbers):\n");
            gets(mt.MediID);
            fflush(stdin);
            printf("Enter Medicine Name:\n");
            gets(mt.MediName);
            fflush(stdin);
            printf("Enter Quantity:\n");
            scanf("%d",&mt.quantity);
            fflush(stdin);
            printf("Enter Price:\n");
            scanf("%f",&mt.price);
            fflush(stdin);
            printf("Enter Expiry Date(dd.mm.yyyy):\n");
            gets(mt.ExpDate);
            fflush(stdin);
            printf("Enter Company:\n");
            gets(mt.Company);
            fflush(stdin);
            printf("Enter Supplier:\n");
            gets(mt.Supplier);
            fflush(stdin);
            printf("Enter Info about medicine:\n");
            gets(mt.info);
            fflush(stdin);
            fseek(pt,sizeof(m),SEEK_CUR);
            fwrite(&mt,sizeof(struct Medicine),1,pt);
            flag=1;
            //aus Schleife aussteigen wenn gesuchter Eintrag gefunden wurde
            break;
        }
        fflush(stdin);
    }
    if(flag==1){
        printf("\n your data has been modified");
    }
    else{
        printf(" \n data is not found");
    }
    fclose(pt);
}
printf("\n Enter any key to go back to medicine menu\n");
getch();
fflush(stdin);
medicine();
Loreenik
  • 21
  • 4
  • 1
    Never use the `gets()` function, it's potentially dangerous. Also, the `fflush()` documentation says that only `stdout` may be flushed, not `stdin`. – Rohan Bari Jun 09 '21 at 18:13
  • What about *debugging* your program first to find what's going wrong, and *then* ask for specific help? Also your title does not match the code: The function does not "edit" any "struct". Despite of that the code indent is just terrible. – U. Windl Jun 10 '21 at 08:48
  • Debugging doesnt work with file handling – Loreenik Jul 05 '21 at 12:04

1 Answers1

2

The fseek is probably wrong. SEEK_CUR is relative but we need to give it a negative offset to seek backwards to the previous/just read position.

Never use gets. The man page says why. But, see also: Why is the gets function so dangerous that it should not be used?

Doing fflush on an input stream is bad juju. It should only be used for output streams. And, with gets is probably unnecessary.

Don't intermix scanf and gets/fgets/fgetc. This just leads to problems.

Rewrite using fgets. You can put that in a common function to avoid replicating code.

Side note: You probably do not want to be calling medicine from within editmed. I assume medicine is the main menu and one of the entries in the menu is to call editmed. Better that the caller of editmed does this [based on a return code from editmed]. Otherwise, you could end up with arbitrary/infinite recursion.


Here's a refactored version that should work better.

It is a simplified version from my answer: Cannot implement Linked List in the given code

I've compiled it but not tested it:

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

// I don't use windows ;-)
#if 1
#define system(_cmd)        do { } while (0)
#define getch(_cmd)     do { } while (0)
#endif

struct Medicine {
    int quantity;
    float price;
    char ExpDate[15];
    char Company[20];
    char Supplier[30];
    char MediName[20];
    char info[1000];
    char MediID[30];
};

// helper macro for askstr calls
#define ASKSTR(_str,_prompt) \
    askstr(_str,sizeof(_str),_prompt)

// askstr -- prompt user for string
char *
askstr(char *buf,size_t buflen,const char *prompt)
{

    // prompt user
    printf("Enter %s: ",prompt);
    fflush(stdout);

    // get an input line
    char *cp = fgets(buf,buflen,stdin);

    // strip newline
    if (cp != NULL)
        buf[strcspn(buf,"\n")] = 0;

    return cp;
}

void
medicine(void)
{
}

// editmed -- edit the medicine file
// RETURNS: -1=error, 0=no change, 1=changed
int
editmed()
{
    FILE *pt;
    int flag = -1;
    struct Medicine m, mt;
    char ID[30];
    char buf[100];

    pt = fopen("mlist.txt", "rb+");
    if (pt == NULL) {
        printf("editmed: file opening error -- %s\n",strerror(errno));
    }
    else {
        system("cls");

        ASKSTR(ID,"Medicine ID to modify");

        flag = 0;

        while (fread(&m, sizeof(struct Medicine), 1, pt) == 1) {
            if (strcmp(ID, m.MediID) == 0) {
                char *cp;

                ASKSTR(mt.MediID,"Medicine ID (only numbers)");

                ASKSTR(mt.MediName,"Medicine Name");

                ASKSTR(buf,"Quantity");
                mt.quantity = strtol(buf,&cp,10);

                ASKSTR(buf,"Price");
                mt.price = strtod(buf,&cp);

                ASKSTR(mt.ExpDate,"Expiry Date(dd.mm.yyyy)");

                ASKSTR(mt.Company,"Company");
                ASKSTR(mt.Supplier,"Supplier");

                ASKSTR(mt.info,"Info about medicine");

// NOTE/BUG: we need to seek _backwards_ from current position
#if 0
                fseek(pt, sizeof(m), SEEK_CUR);
#else
                fseek(pt, -sizeof(m), SEEK_CUR);
#endif

                fwrite(&mt, sizeof(struct Medicine), 1, pt);
                flag = 1;
                // aus Schleife aussteigen wenn gesuchter Eintrag gefunden wurde
                break;
            }
#if 0
            fflush(stdin);
#endif
        }
        if (flag == 1) {
            printf("\n your data has been modified");
        }
        else {
            printf(" \n data is not found");
        }
        fclose(pt);
    }

#if 0
    printf("\n Enter any key to go back to medicine menu\n");
    getch();
    fflush(stdin);
    medicine();
#else
    ASKSTR(buf,"any key to go back to medicine menu");
    return flag;
#endif
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • thanks man helps me a lot i tried scanf instead of gets but somehow my were written the wrong way into my file .. i will try to change it though thanks – Loreenik Jun 09 '21 at 20:17
  • Read all input with `fgets()`, e.g. `fgets (ExpoDate, sizeoof Expodate, stdin);` If you need to trim the `'\n'` from the end, just `ExpoDate[strcspn (ExpoDate, "\n")] = 0;` If you need to parse values from the string, then pass it to `sscanf()` (just as you would use `scanf()`, but providing `ExpoDate` as the first argument). – David C. Rankin Jun 09 '21 at 20:29
  • I put a - before the sizeof(m) to get the file pointer going back instead of forward in fseek(pt,sizeof(m),SEEK_CUR); now it actually works – Loreenik Jun 09 '21 at 20:41
  • i will now change the gets – Loreenik Jun 09 '21 at 20:41