Search code examples
cpointersstructdynamic-memory-allocation

Error when adding another record to dynamic memory database


My task is to initialize a struct in a header with some data. Then using pointers, add/remove data by malloc-ing bigger/smaller chunks and copying the data over.

Currently, my addRecord function doesn't work as it always seems to add the same crap (Part of record number 1):

Name =

Fire Number = attan (Seems to be part of Manhattan)

Street = ork (Seems to be part of New York)

City = cret (Seems to be part of Secret)

State = tan (Seems to be part of Manhattan)

What am I doing wrong?

My header:

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

struct structPointer{
    char name[51];
    char fireNumber[11];
    char street[26];
    char city[26];
    char state[26];
};

My c file:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "myData.h"

struct structInit *sP;
struct structInit *sSP;
int recordNumber = 0;
int numberOfAccesses = 0;

int main(void) {
    sP = (struct structInit *) malloc(5 * sizeof(struct structInit));
    sSP = sP;

    memcpy(sP->name,"Adam Baum",51);
    memcpy(sP->fireNumber,"N1234",11);
    memcpy(sP->street,"Top Secret",26);
    memcpy(sP->city,"Manhattan",26);
    memcpy(sP->state,"New York",26);
    sP++;
    recordNumber++;
    memcpy(sP->name,"Adam Zapel",51);
    memcpy(sP->fireNumber,"S4321",11);
    memcpy(sP->street,"Throat",26);
    memcpy(sP->city,"Manhattan",26);
    memcpy(sP->state,"New York",26);
    sP++;
    recordNumber++;
    memcpy(sP->name,"Al Bino",51);
    memcpy(sP->fireNumber,"W1234",11);
    memcpy(sP->street,"White",26);
    memcpy(sP->city,"Anchorage",26);
    memcpy(sP->state,"Alaska",26);
    sP++;
    recordNumber++;
    memcpy(sP->name,"Anne Teak",51);
    memcpy(sP->fireNumber,"E4321",11);
    memcpy(sP->street,"Oak",26);
    memcpy(sP->city,"Woodville",26);
    memcpy(sP->state,"Wisconsin",26);
    sP++;
    recordNumber++;
    memcpy(sP->name,"Barb Dwyer",51);
    memcpy(sP->fireNumber,"N1234",11);
    memcpy(sP->street,"Keepout",26);
    memcpy(sP->city,"Kilgore",26);
    memcpy(sP->state,"Texas",26);
    recordNumber++;
    sP = sSP;

    int sel;
    while (1){
    printf("MENU\n");
    printf("=====\n");
    printf("1. Print All Records\n");
    printf("2. Print Number of Records\n");
    printf("3. Print Size of Database\n");
    printf("4. Add Record\n");
    printf("5. Delete Record\n");
    printf("6. Print Number of Accesses to Database\n");
    printf("7. Exit\n");
    printf("=====\n");
    printf("Enter selection: ");
    scanf("%d", &sel);
    printf("\n");
        switch(sel){
            case 1:
                numberOfAccesses++;
                printAllRecords(sP);
                break;
            case 2:
                numberOfAccesses++;
                fprintf(stderr,"There are a Total of %d records.\n\n", recordNumber);
                break;
            case 3:
                numberOfAccesses++;
                printSizeOfDatabase(sP);
                break;
            case 4:
                numberOfAccesses++;
                sP = sSP;
                addRecord(sP);
                break;
            case 5:
                numberOfAccesses++;
                deleteRecord(sP);
                break;
            case 6:
                numberOfAccesses++;
                fprintf(stderr,"The total number of Accesses is %d\n\n", numberOfAccesses);
                break;
            case 7:
                exit(0);
            default:
                printf("Error: Input was not a valid selection.\n\n");
                break;
        }
    }
return 0;
}

int printAllRecords(struct structInit *structPointer){
    int i;
    structPointer = sSP;
    printf("All Records: \n");
    for(i=1;i<=recordNumber;i++){
    printf("Record Number: %d\n", i);
    fprintf(stderr, "Name = \%s\n", structPointer-> name);
        fprintf(stderr, "Fire Number = \%s\n", structPointer-> fireNumber);
        fprintf(stderr, "Street = \%s\n", structPointer-> street);
        fprintf(stderr, "City = \%s\n", structPointer-> city);
        fprintf(stderr, "State = \%s\n\n", structPointer-> state);
        structPointer++;
    }
    return 1;
}

int printSizeOfDatabase(struct structInit *structPointer) {
    int size = 0;
    int i;
    for (i=1;i<=recordNumber;i++) {
    size += sizeof(structPointer->name);
    size += sizeof(structPointer->fireNumber); 
    size += sizeof(structPointer->street);
    size += sizeof(structPointer->city);
    size += sizeof(structPointer->state);
    structPointer++;
        }
    fprintf(stderr, "The size of the database is %d bytes.\n\n", size);
    return size;
}

int addRecord(struct structInit *structPointer){
    char entryName;
    char entryFireNumber;
    char entryStreet;
    char entryCity;
    char entryState;
    recordNumber++;
    struct structInit *theStruct;
    theStruct = (struct structInit *) malloc ((recordNumber+1) * sizeof(struct structInit));
    int i;
    for (i=1;i<recordNumber;i++){
        memcpy(theStruct->name,structPointer->name,51);
        memcpy(theStruct->fireNumber,structPointer->fireNumber,11);
        memcpy(theStruct->street,structPointer->street,26);
        memcpy(theStruct->city,structPointer->city,26);
        memcpy(theStruct->state,structPointer->state,26);
        /*if(i==recordNumber){
            theStruct++;}
        else{
            theStruct++;
            structPointer++;}*/
    theStruct++;
    structPointer++;
    }
    theStruct++;

    printf("Enter the Name of the New Record: \n");
    scanf("%s",&entryName);
    memcpy(theStruct->name,&entryName,51);
    printf("Enter the Fire Number of the New Record: \n");
    scanf("%s",&entryFireNumber);
    memcpy(theStruct->fireNumber,&entryFireNumber,11);
    printf("Enter the Street of the New Record: \n");
    scanf("%s",&entryStreet);
    memcpy(theStruct->street,&entryStreet,26);
    printf("Enter the City of the New Record: \n");
    scanf("%s",&entryCity);
    memcpy(theStruct->city,&entryCity,26);
    printf("Enter the State of the New Record: \n");
    scanf("%s",&entryState);
    memcpy(theStruct->state,&entryState,26);
    structPointer=theStruct;
    printf("Record has been added.\n\n");
    return 0;
}

int deleteRecord(struct structInit *structPointer){
    struct structInit *anotherStruct;
    anotherStruct = (struct structInit *) malloc ((recordNumber+1) * sizeof(struct structInit));
    int i;
    for(i=0;i<5;i++){
    memcpy(anotherStruct->name,structPointer->name,51);
    memcpy(anotherStruct->fireNumber,structPointer->fireNumber,11);
    memcpy(anotherStruct->street,structPointer->street,26);
    memcpy(anotherStruct->city,structPointer->city,26);
    memcpy(anotherStruct->state,structPointer->state,26);
    structPointer++;
    }
    structPointer=anotherStruct;
    recordNumber--;
    printf("Record has been deleted.\n\n");
    return 0;
}

Solution

  • At a glance:

    The %s format specifier for scanf specifies a pointer to the first element of an array of char.
    You're passing a pointer to one char.
    It's just bad luck that the program doesn't crash completely.

    You want

    char entryName[51];
    /* ... */
    printf("Enter the Name of the New Record: \n");
    scanf("%s", entryName);
    

    and similar for the rest of the inputs.

    Replace memcpy with strncpy - you shouldn't copy anything from outside the source object.

    If you use realloc you can get rid of the entire copying loop when you expand your table.

    Assigning to a parameter doesn't modify the value of the variable whose value you passed in.
    This is as true for pointers as it is for everything else.
    If you want to modify a variable, pass a pointer to it:

    int addRecord(struct structInit **structPointer)
    {
       /* ... */
       *structPointer = theStruct;
       /* ... */
    }
    

    You don't need to do a memberwise memcpy between structs - in fact you don't need memcpy at all, since assignment works:

    struct structInit a = /* ... */;
    struct structInit b = /* ... */;
    a = b; /* OK */
    

    You need to make up your mind about whether to use global variables or parameters.
    In particular, printAllRecords disregards the value of its parameter completely.

    deleteRecord assumes that there are five records in your table.

    You can also replace printSizeOfDatabase with this:

    int printSizeOfDatabase() {
        int size = recordNumber * sizeof(struct structInit);
        fprintf(stderr, "The size of the database is %d bytes.\n\n", size);
        return size;
    }