2014-10-03 2 views
1

레코드를 추가하거나 삭제 한 후 데이터베이스를 업데이트하는 방법을 파악하려고합니다. 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

데이터베이스은 구조체의 배열이며 레코드를 추가하거나 제거 할 때 새 배열을 할당하고 관련 레코드를 새 배열에 복사 한 다음 추가 복사본 새로운 기록.

모든 것이 괜찮지 만 (매우 효율적이 아니더라도) 전역 변수 headPtr이 새 배열을 가리 키지 않는 것 같습니다. 단순히 이전 데이터베이스를 비우고 headPtr이 새 데이터베이스를 가리 키도록하십시오.

당신은 addRecorddeleteRecord의 마지막에 이런 일이 있어야합니다, 당신의 deleteRecord 기능이 잘못

free(headPtr); 
headPtr = tempHead; /* for addRecord */ 

headPtr = newDbHead; /* for deleteRecord */ 

그리고 독립적으로 georgem에 의해주의 문제 (치명적 안)의 : 당신이 레코드를 복사 첫 번째 레코드를 가리 키지 않고 새 레코드의 이전 데이터베이스 적어도 다음을 사용해야합니다 :

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; 
} 
+0

왜'* newDb = * ptr; '대신'memcpy()'를 사용해야합니까? 나는 당신의 '단편적인 것이 아닌 전체 구조 복사'에 동의하지만, 구조 복사를하지 않은 컴파일러 (1983 년에 사용 된 것)를 찾기 위해 80 년대로 되돌아 가야 할 것입니다. –

+0

많은 분들에게 sooooo 고맙습니다 !!!!! 나는 내가이 모든 시간을 보낸 후에 일하도록했다 !!! 정말 고맙습니다!!! 그것은 지금 일한다! !!! 나는 너를 얼마나 고맙게 여기지 말할 수 없다! 교수님은 여러 번 도움을 청하신 후 간신히 나를 도왔습니다. 고맙습니다! – ThomasM

4

그것은 당신이 제공하는 매우 큰 샘플,하지만 하나,이를 위해 :

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

가 확인하지 않는 것 나에게. 크기는 100이지만 문자 배열 "Bill" 은 5 바이트입니다 (널 종결자는 1). 그래서 나는 배열을 지난 을 읽으 려 시도 할 것이라고 생각합니다. 이 경우 strcpy을 시도해 볼 수 있으며 정확히 5 바이트를 복사합니다.

또한 Serge Ballesta가 지적한 바와 같이 sizeofDb 방법과 비슷한 문제가 있습니다. 데이터베이스의 시작 부분에 포인터를 설정해야합니다.

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

그렇지 않으면 나중에 역 참조 할 대상이 명확하지 않습니다. 실제로 sizeofDb 내부에서 충돌하지 않는 이유는 Is dereferencing null pointer valid in sizeof operation입니다. 그러나 논리적으로는 여전히 처음 부분을 가리켜 야합니다.

관련 문제