0

I have a C program that is meant to save, edit and delete contacts and save them to a binary file. The struct for the contact is defined as such:

    struct Contact {
        unsigned long phone_number;
        long first_name_posn;
        long last_name_posn;
        long company_name_posn;
        long email_posn;
        long next;
    }

Each value apart from the phone_number holds the location of the information on the file, and the information is written right after. Now when the program is running, I read all the contacts into a dynamic array. The function below is meant to add an additional contact to the array and stores it. However, when I start with zero contacts and add one, it's fine. But when I attempt to add a second contact it appears to overlap the first one and causes the program to read the wrong information.

I believe it has something to do with my realloc statement, although I have no idea what could be wrong. I tried to create a second array and realloc to that array, but that also failed.

int addContact(Contact *contacts, FILE *fptr, int size)
{
    char *fName, *lName, *company, *email;
    unsigned long phone;
    long next;
    char input[MAX_STRING_SIZE];

    /* Gets the first name */
    printf("First Name: ");
    fgets(input, MAX_STRING_SIZE, stdin);
    fName = toPointer(input);

    /*Gets the last name or company name */
    do
    {
        printf("Last Name: ");
        fgets(input, MAX_STRING_SIZE, stdin);
        lName = toPointer(input);

        printf("Company Name: ");
        fgets(input, MAX_STRING_SIZE, stdin);
        company = toPointer(input);

    } while ((lName[0] == '\0' || lName[0] == '\n') && (company[0] == '\0' || company[0] == '\n'));

    /* Gets the phone number */
    do
    {
        printf("Phone Number (enter only numbers): ");
        fgets(input, MAX_STRING_SIZE, stdin);

        if (input[0] != '\0' && input[0] != '\n')
        {
            sscanf(input, "%ld", &phone);
        }
    } while ((phone < 1000000 || phone > 9999999) && (phone < 1000000000 || phone > 9999999999));

    do
    {
        printf("Email: ");
        fgets(input, MAX_STRING_SIZE, stdin);
        email = toPointer(input);

    } while (!isValidEmail(email));

    printf("Action: ");
    fgets(input, MAX_STRING_SIZE, stdin);
    lowerCase(input);

    if (input[0] == 's' && input[1] == '\0')
    {
        next = getNext(fptr);
        printf("Size: %d\n", size);
        contacts = realloc(contacts, sizeof(Contact) * (size+1));
        fseek(fptr, 0, SEEK_END);

        /* Calculates the position for the contact */
        contacts[size].phone_number = phone;
        contacts[size].first_name_posn = next + sizeof(Contact);
        contacts[size].last_name_posn = next + sizeof(Contact) + (sizeof(char) * (strlen(fName)+1));
        contacts[size].company_name_posn = next + sizeof(Contact) + (sizeof(char) * (strlen(fName)+1)) + (sizeof(char) * (strlen(lName)+1));
        contacts[size].email_posn = next + sizeof(Contact) + (sizeof(char) * (strlen(fName)+1)) + (sizeof(char) * (strlen(lName)+1)) + (sizeof(char) * (strlen(company)+1));
        contacts[size].next = next + sizeof(Contact) + (sizeof(char) * (strlen(fName)+1)) + (sizeof(char) * (strlen(lName)+1)) + (sizeof(char) * (strlen(company)+1)) + (sizeof(char) * (strlen(email)+1));

        fwrite(&contacts[size], sizeof(Contact), 1, fptr);
        fwrite(fName, sizeof(char) * (strlen(fName)+1), 1, fptr);
        fwrite(lName, sizeof(char) * (strlen(lName)+1), 1, fptr);
        fwrite(company, sizeof(char) * (strlen(company)+1), 1, fptr);
        fwrite(email, sizeof(char) * (strlen(email)+1), 1, fptr);

        size++;
    }

    free(fName);
    free(lName);
    free(company);
    free(email);

    return size;
}

If I enter these two contacts:

First Name: John

Last Name: Smith

Company: Rick's

Phone: 1234567899

Email: jsmith@hotmail.com

First Name: Bob

Last Name: Evergreen

Company:

Phone: 5194567895

Email: bobgreen@gmail.com

This will rid the first name of John, and change the phone number to 6445449192 other staying the same for that contact. For the second contact, all the information is "om", and the phone number is 64.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • 2
    Note that [`while (!feof(file))` is always wrong](https://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong). You could sensibly forget that `feof()` exists — you, and every teacher of C. You test the I/O operation. Use: `while (fgets(input, sizeof(input), stdin))` to control the loop. – Jonathan Leffler Apr 02 '19 at 14:54
  • 1
    It seems reasonably likely that the main problem is in the code for reading back contacts, but you've provided only the code for writing them out. We can help you much better if you provide a [mcve] that demonstrates the problem. Note well that this is not just a selection of possibly-relevant functions from your program -- it takes some effort to find or (re)write the essentials of the problem. The link earlier in this comment leads to a more detailed discussion. – John Bollinger Apr 02 '19 at 15:11
  • I note that you `realloc()` the data pointed at by `contacts`, but you don't have a way to relay any change in base address back to the calling code. If the `realloc()` moves the data, you're hosed because the calling code doesn't know that things have changed. You could use a pointer to pointer argument, perhaps, or you could use a structure type to describe the array (pointer to base, number of allocated items, number of items in use) and pass a pointer to the structure to the function, and update the fields in that structure. – Jonathan Leffler Apr 02 '19 at 15:31
  • @thomasdickey Add an answer. Don't edit the question with a solution. – Mark Tolonen Mar 23 '23 at 22:14
  • (a) this is probably a duplicate, (b) OP is unlikely to respond. – Thomas Dickey Mar 23 '23 at 22:20

0 Answers0