我编写了一个程序,其中涉及为客户创建银行帐户。但是,当我从该帐户“存入”资金时,它将更新,但它将添加该更新的帐户并保留旧的帐户,如下所示:
First Name: her
Middle Name: m.
Last Name: an
Account Number: 1
Balance: $5600.00
First Name: her
Middle Name: m.
Last Name: an
Account Number: 1
Balance: $11600.00
我相信在我的switch语句之前,它将在我的代码开头处理我的“ fopen”。如果我将“ ab +”更改为除此之外的任何内容,则不会保存我的“帐户”。并在我再次运行可执行文件时将其删除。
FILE *aPtr;
aPtr = fopen( "accounts.dat", "ab+");
if ( aPtr == NULL ) {
printf ( "File could not be opened" );
exit(1);
}
fseek( aPtr, 0, SEEK_SET ); /* Moving pointer to start of file*/
while ( fread(accounts + i, sizeof(data), 1, aPtr) )
i++;
n = i; /* Num. of records in file */
下面提供了当我“保存”时的代码,我相信复制数据的原因可能与我使用“ fwrite”的方式以及保存位置有关。但是我似乎无法弄清楚问题是什么。
在正确方向上的任何帮助将不胜感激。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char first[15];
char middle[2];
char last[15];
float balance;
long int acct;
}data;
int main()
{
int choice = -1, i = 0, n = 0;
long int number;
double amount;
data accounts[50];
FILE *aPtr;
aPtr = fopen( "accounts.dat", "ab+");
if ( aPtr == NULL ) {
printf ( "File could not be opened" );
exit(1);
}
fseek( aPtr, 0, SEEK_SET ); /* Moving pointer to start of file*/
while ( fread(accounts + i, sizeof(data), 1, aPtr) )
i++;
n = i; /* Num. of records in file */
do
{
printf ( "Select Option\n" );
printf ( "0: Exit\n1: Deposit\n2: Withdrawl\n3: Add Account\n4: Remove Account\n5: Balance Inquiry\n6: View Accounts\n: ");
scanf ( "%d", &choice );
printf("\n\n");
switch (choice)
{
case 0: /* Exit */
fclose ( aPtr );
break;
case 1: /* Deposit*/
fseek( aPtr, 0, SEEK_SET );
printf ( "Enter account number:\n" );
scanf ( "%ld", &number );
printf ( "Enter amount to be deposited:\n" );
scanf ( "%lf", &amount );
for ( i = 0; i < n; i++ ) {
if ( accounts[i].acct == number ) {
accounts[i].balance = accounts[i].balance + amount;
fseek( aPtr, i*sizeof(data), SEEK_SET ); /* Pointer goes to accountlocation in file*/
fwrite( &accounts[i], sizeof(data), 1, aPtr ); /* Write modified account into file */
printf("New Balanace: $%.2f\n\n", accounts[i].balance);
break;
}
}
if ( i == n) {
printf("Account does not exist\n\n");
break;
}
break;
case 2: /* Withdrawal */
fseek( aPtr, 0, SEEK_SET);
printf("Enter the account to withdrawal:\n");
scanf("%ld", &number);
printf("Enter amount to withdrawal\n");
scanf("%lf", &amount);
for (i = 0; i < n; i++) {
if (accounts[i].acct == number) {
if (accounts[i].balance < amount) { /* checks for required balance */
printf ("Not a sufficient balance\n\n");
break;
}
accounts[i].balance = accounts[i].balance - amount;
fseek(aPtr, i * sizeof(data), SEEK_SET);
fwrite(accounts+i, sizeof(data), 1, aPtr);
printf("New Balance: $%.2f\n\n", accounts[i].balance);
break;
}
}
if(i == n )
printf("Account number does not exist\n\n");
break;
case 3: /* Add */
printf ("Enter account number (1-99):\n");
scanf ("%ld", &number);
for (i = 0; i < n; i++) {
if (accounts[i].acct == number) {
printf("Account already exist\n\n");
break;
}
}
if (i == n) {
printf("Enter First Name:\n");
scanf("%s", accounts[i].first);
printf("Enter Middle Initial:\n");
scanf("%s", accounts[i].middle);
printf("Enter Last Name:\n");
scanf("%s", accounts[i].last);
accounts[i].acct = number;
printf("Enter Deposit Amount:\n");
scanf("%f", &accounts[i].balance);
printf("\n\n");
fseek(aPtr, 0, SEEK_END);
fwrite(accounts+i, sizeof(data), 1, aPtr);
n++;
}
break;
case 4: /* Delete */
fseek(aPtr, 0, SEEK_SET);
printf("Enter account wished to be deleted:\n");
scanf("%ld", &number);
for(i = 0; i < n; i++) {
if(accounts[i].acct == number)
break;
}
if( i == n ) {
printf("Account number does not exist\n\n");
}
else {
while ( i < n ) {
strcpy(accounts[i].first, accounts[i+1].first);
strcpy(accounts[i].middle, accounts[i+1].middle);
strcpy(accounts[i].last, accounts[i+1].last);
accounts[i].acct = accounts[i+1].acct;
accounts[i].balance = accounts[i+1].balance;
n--;
}
aPtr = fopen("accounts.dat", "wb");
for(i = 0; i < n; i++)
fwrite(accounts+i, sizeof(data), 1, aPtr); /* Writes records w/o deleted record */
fclose(aPtr);
fopen("accounts.dat", "ab+");
}
break;
case 5: /* Print Required Account */
printf("Enter Account Number:\n");
scanf("%ld", &number);
for(i = 0; i < n; i++) {
if(accounts[i].acct == number) {
printf("First Name: %s\n", accounts[i].first);
printf("Middile Initial: %s.\n", accounts[i].middle);
printf("Last Name: %s\n", accounts[i].last);
printf("Account Number: %ld\n", accounts[i].acct);
printf("Balance: $%.2f\n\n", accounts[i].balance);
printf("\n\n");
break;
}
}
if ( i == n ) {
printf("Account does not exist\n\n");
break;
}
break;
case 6: /* Print All */
for(i = 0; i < n; i++) {
printf("First Name: %s\n", accounts[i].first);
printf("Middle Name: %s.\n",accounts[i].middle);
printf("Last Name: %s\n", accounts[i].last);
printf("Account Number: %ld\n", accounts[i].acct);
printf("Balance: $%.2f\n", accounts[i].balance);
printf("\n\n");
}
}
} while ( choice != 0 );
return 0;
}
答案 0 :(得分:2)
代码缺少错误检查,因此未能防止缓冲区溢出。
scanf("%s", ...
就像弱gets()
。使用宽度限制。
typedef struct {
char first[15];
char middle[2];
char last[15];
float balance;
long int acct;
} data;
//scanf("%s", accounts[i].first);
scanf("%14s", accounts[i].first);// Max 14 characters to read and save a string in first[15]
//scanf("%s", accounts[i].middle);
scanf("%1s", accounts[i].middle);
//scanf("%s", accounts[i].first);
scanf("%14s", accounts[i].first);
更好的代码将检查返回值以确保其为1。
if (scanf("%14s", accounts[i].first) != 1) {
printf("Bad input\n");
return EXIT_FAILURE; // or other error handing.
}
甚至更好的代码也将废弃所有scanf()
的调用,并替换为fgets()
和可靠的解析-但将其保留一天。
在"m."
输入char middle[2];
的情况下,代码遇到未定义的行为(UB)。还有wheels fell off the bus。代码可能需要更大的名称字符数组。在最长名中搜索一些想法。
存在其他问题。
“平衡”->“平衡”
避免使用float
来赚钱。建议使用最小货币单位的double
或long long
。这是一个涉及许多问题的深层问题,至少不要使用float
。
名称可能包含空格。 "%s"
对此不起作用。