如何更新结构/记录的数据库

时间:2014-10-03 20:39:33

标签: c pointers struct

我试图找出在添加或删除记录后如何更新数据库。我在添加和删除记录函数中使用了fprintf语句,它让我知道元素数据实际被添加,由于某种原因,添加将起作用(删除记录没有),但是当我去打印数据库时,它是不打印新数据库。如何更新数据库并相应打印?我是否需要一个全局变量来接收新数据库?

标题文件:

 #ifndef myStruct
 #define myStruct

struct creditCard
{
 char firstName[100]; 
 char lastName[100];
 char cardNumber[17]; //TA advised to use string since 16 digits will overflow in plain integer
 char expMonth[10];
};

//function headers below
int printCreditCard(struct creditCard *);

int sizeOfDb(struct creditCard *);

int countRecords(struct creditCard *);

int deleteRecord(struct creditCard *);

int addRecord(struct creditCard *);

 #endif

主程序:

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

int accesses = 0; //number of times database was manipulated
int count = 0;  //used to count how many records there are; we always start at 4
//int size = 0; //used to tell us how big the database is
struct creditCard *ptr;  //chunk of memory for each record/structure
struct creditCard *headPtr; //chunk of memory for the first records/structure

int main(void)
{
    ptr = (struct creditCard *) malloc(4 * sizeof(struct creditCard));
    headPtr = ptr;

memcpy(ptr->firstName,"Bob",100);
memcpy(ptr->lastName,"Marley",100);
memcpy(ptr->cardNumber,"0000000000000000",17);
memcpy(ptr->expMonth,"September", 10);
ptr++;
count = count+1;

memcpy(ptr->firstName, "Will", 100);
memcpy(ptr->lastName, "Smith", 100);
memcpy(ptr->cardNumber,"1111111111111111",17);
memcpy(ptr->expMonth, "October", 10);
ptr++;
count = count+1;

memcpy(ptr->firstName, "Bill", 100);
memcpy(ptr->lastName, "Gates", 100);
memcpy(ptr->cardNumber,"2222222222222222",17);
memcpy(ptr->expMonth, "January", 10);
ptr++;
count = count+1;

memcpy(ptr->firstName, "Steve", 100);
memcpy(ptr->lastName, "Jobs", 100); 
memcpy(ptr->cardNumber,"3333333333333333",17);
memcpy(ptr->expMonth, "May", 10);
count = count+1;

while (1)
{
//  headPtr = ptr;  //put the newest database into headPtr so it points to the first record in  that database
//  ptr = headPtr;  //start the database back at the first record
//countRecords(ptr); //update the count of the current database

    int sel;
    printf("MAIN MENU\n");
    printf("=====\n");
    printf("1.  Select 1 to print all records.\n");
    printf("2.  Select 2 to print number of records .\n");
    printf("3.  Select 3 to print size of database.\n");
    printf("4.  Select 4 to add record.\n");
    printf("5.  Select 5 to delete record.\n");
    printf("6.  Select 6 to print number of accesses to database.\n");
    printf("7.  Select 7 to Exit.\n");
    printf("Enter Your Selection:  \n");

    scanf("%d", &sel); //get user input;

    if (sel == 1)
{   
    printCreditCard(ptr);
    accesses++;
}
else if (sel == 2)
{
    fprintf(stderr,"Number of records in the database is %d records\n", count); //pulls value of count from global updated variable
        accesses++;

}
else if (sel == 3)
{
    sizeOfDb(ptr);
    accesses++;
}
else if (sel == 4)
{
    ptr = headPtr;
    addRecord(ptr);
    accesses++;
}
else if (sel == 5)
{
    deleteRecord(ptr);
    accesses++;
}
else if (sel == 6)
{
    fprintf(stderr,"Number of accesses to the database is %d\n", accesses);
    accesses++;
}
else if (sel == 7)
{
            printf("Now Exiting.\n");
    return 0;
}
else
{
    printf("Invalid input, please select a valid option.\n");
    break; //go back to the main menu
}
}
}

//functions defined below
int sizeOfDb(struct creditCard *card2)
{
int size = 0;
int j;
    for (j = 1; j <= count; j++) 
    {
        size += sizeof(card2->firstName); //get the size of each element
    size += sizeof(card2->lastName); 
    size += sizeof(card2->cardNumber);
    size += sizeof(card2->expMonth);
    card2++;
    }
    //loop through each record and get sizeof() of each record
fprintf(stderr, "Total Size of the Database is %d bytes.\n", size);
return size;
}

int addRecord(struct creditCard *card3)
{
  char fName[100];
  char lName[100];
  char number[17];
  char month[10];

count = count+1;
fprintf(stderr, "count is %d \n", count);
int p;
struct creditCard *tempStruct;
struct creditCard *tempHead;
tempStruct = (struct creditCard *) malloc (count * sizeof(struct creditCard)); //allocate memory to a dummy record
tempHead = tempStruct;  
card3 = headPtr; //start at the beginning of the old database
for (p = 1; p < count; p++) //copies the old database in the new database up to the record before the newly allocated record
{ 
    memcpy(tempStruct->firstName, card3->firstName, 100);
    memcpy(tempStruct->lastName, card3->lastName, 100);
    memcpy(tempStruct->cardNumber, card3->cardNumber, 17);
    memcpy(tempStruct->expMonth, card3->expMonth, 10);
    fprintf(stderr, "first name is %s\n", tempStruct->firstName);
    if (p == count-1)  //if we are on the record before the last record, then only increment    tempStruct, card3 has one less record than the new database has
    {
        tempStruct++;
    }
    else
    {
        tempStruct++;
        card3++;
    }
}
printf("Please enter your first name.\n");
scanf("%s", fName);
memcpy(tempStruct->firstName, fName, 100);
    printf("Please enter your last name.\n");
    scanf("%s", lName);
    memcpy(tempStruct->lastName, lName, 100);//put first name in struct
    printf("Please enter your 16 digit credit card number with no spaces.\n");
scanf("%s", number);
    memcpy(tempStruct->cardNumber, number, 17);//put first name in struct
    printf("Please enter the month in which your credit card expires.\n");
    scanf("%s", month);
    memcpy(tempStruct->expMonth, month, 10);//put first name in struct
fprintf(stderr, "tempStruct first name is %s\n", tempStruct->firstName);
fprintf(stderr, "tempStruct last name is %s\n", tempStruct->lastName);
fprintf(stderr, "tempStruct card number is %s\n", tempStruct->cardNumber);
fprintf(stderr, "tempStruct exp month is %s\n", tempStruct->expMonth);

tempStruct = tempHead;
card3 = tempStruct;  //put the new database in place of the old database

//free(tempStruct); //clear memory for the dummy record because we don't need it anymore
return 0;
}

int deleteRecord(struct creditCard *card4)  //goes to the last record in the database and clears    the memory for it, essentially deleting it
{
int b;

count = count-1;
int l;
struct creditCard *newDb;  //will hold the new database with one less record at the end
struct creditCard *newDbHead;
newDb = (struct creditCard *) malloc(count * sizeof(struct creditCard));
newDbHead = newDb;
for (l = 1; l <= count; l++)
{ 
    memcpy(newDb->firstName,card4->firstName,100);
    memcpy(newDb->lastName,card4->lastName,100);
    memcpy(newDb->cardNumber,card4->cardNumber,17);
    memcpy(newDb->expMonth,card4->expMonth,10);
    if (l == count)
    {
        continue;
    }
    else
    {
        card4++;
        newDb++;
    }
}
newDb = newDbHead;  //start back at the first record
for (b = 1; b <= count; b++)
{
    fprintf(stderr, "first name for the current record is %s\n", newDb->firstName);
    newDb++;
}
card4 = newDb;  //put the new database into ptr to hold as the new database
return 0;
} 

int printCreditCard(struct creditCard *card)
{
 card = headPtr;  //start at the beginning of the database
 int i;
 if (count == 0)
{
printf("The database is empty\n");
return 0;
}
else
{
for (i = 1; i <= count; i++)
{
        printf("Credit Card Record %d\n", i);
    fprintf(stderr, "First Name = \%s\n", card-> firstName);
            fprintf(stderr, "Last Name = \%s\n", card-> lastName);
            fprintf(stderr, "Card Number = \%s\n", card-> cardNumber);
            fprintf(stderr, "Expiration Date = \%s\n\n", card-> expMonth);
    card++;  //go to the next record to print
 }
}
 return 1; //we have now printed all records, go to main menu.
}

2 个答案:

答案 0 :(得分:4)

您提供了相当大的样本,但仅举一例:

memcpy(ptr->firstName, "Bill", 100);

对我来说似乎没问题。你指定大小100,但字符数组&#34;比尔&#34; 是5个字节长(1为空终止符)。所以我认为它会尝试阅读 过了阵列。在这种情况下,您可以尝试strcpy,这将完全复制 5个字节。

同样如Serge Ballesta所指出,sizeofDb内部存在类似问题 方法。您应该将指针设置为数据库的开头:

int sizeOfDb(struct creditCard *card2)
{
      card2=headPtr;
      ...

否则不清楚你之后解除了什么。实际上,它之后在sizeofDb内没有崩溃的原因是由于:Is dereferencing null pointer valid in sizeof operation。 但从逻辑上讲,它应该仍然指向开头。

答案 1 :(得分:2)

如果我已正确理解您的逻辑,数据库是一个struct数组,当您添加或删除记录时,您将分配一个新数组,将相关记录复制到新数组,以及添加复制新记录。

一切都很好(即使效率不高),但似乎你永远不会让全局变量headPtr指向新数组。您只需释放旧数据库并使headPtr指向新数据库。

addRecorddeleteRecord

结尾处应该有这样的内容
free(headPtr);
headPtr = tempHead; /* for addRecord */

headPtr = newDbHead; /* for deleteRecord */

独立于georgem注意到的问题(不应该是致命的),您的deleteRecord函数是错误的:您从旧数据库复制记录而不首先指向第一条记录。你应该至少使用:

int deleteRecord(struct creditCard *card4)  //goes to the last record in the database and clears    the memory for it, essentially deleting it
{
int b;

count = count-1;
int l;
struct creditCard *newDb;  //will hold the new database with one less record at the end
struct creditCard *newDbHead;
newDb = (struct creditCard *) malloc(count * sizeof(struct creditCard));
newDbHead = newDb;
ptr = headPtr;
for (l = 1; l <= count; l++)
{
    if (ptr == card4) ptr++;
    /* no use to copy element by element : just copy full struct
    memcpy(newDb->firstName,ptr->firstName,100);
    memcpy(newDb->lastName,ptr->lastName,100);
    memcpy(newDb->cardNumber,ptr->cardNumber,17);
    memcpy(newDb->expMonth,ptr->expMonth,10); */
    /* memcpy(newDb, ptr, sizeof(creditCard)); */
    /* even better, thanks to  Jonathan Leffler */
    *newDb++ = *ptr++;
}
newDb = newDbHead;  //start back at the first record
for (b = 1; b <= count; b++)
{
    fprintf(stderr, "first name for the current record is %s\n", newDb->firstName);
    newDb++;
}
card4 = newDb;  //put the new database into ptr to hold as the new database
free(headPtr);
headPtr = newDbHead;
return 0;
}