C Tutorial
C Project: Bank Account
A tiny account with deposit, withdraw, and balance. Withdrawals cannot go below zero.
What you will build
Each account is a struct: an owner name and a balance. Deposit adds money when the amount is positive. Withdraw subtracts money only when the amount is positive and not larger than the current balance. The balance must never go negative.
The demo keeps a small array of accounts and runs a script of deposits and withdrawals. No disk files, no threads. Compile with Try it in C at /c/try.
The account record
A struct groups the fields. The name lives in a char array. The balance is adouble so cents can be stored as fractional pounds or dollars. Print it with two digits after the point.
Example
#include <stdio.h>
struct Account {
char owner[24];
double balance;
};
int main(void) {
struct Account a = {"Ada", 100.00};
printf("%s has %.2f\n", a.owner, a.balance);
a.balance = a.balance + 25.50;
printf("after deposit %.2f\n", a.balance);
return 0;
}Adding in main works, but it skips the rules. A helper can refuse a negative deposit. Withdraw needs the same kind of gate.
Deposit and withdraw
Pass a pointer to the account so the function can change the stored balance. a->balance is the balance field of the account you pointed at. Return 1 when the operation is applied, 0 when it is refused. Never set the balance below zero.
Example
#include <stdio.h>
struct Account {
char owner[24];
double balance;
};
int deposit(struct Account *a, double amount) {
if (amount <= 0.0) {
return 0;
}
a->balance += amount;
return 1;
}
int withdraw(struct Account *a, double amount) {
if (amount <= 0.0 || amount > a->balance) {
return 0;
}
a->balance -= amount;
return 1;
}
int main(void) {
struct Account a = {"Ada", 100.00};
printf("start %.2f\n", a.balance);
printf("deposit 40: %s now %.2f\n",
deposit(&a, 40.00) ? "ok" : "no", a.balance);
printf("withdraw 200: %s now %.2f\n",
withdraw(&a, 200.00) ? "ok" : "no", a.balance);
printf("withdraw 25: %s now %.2f\n",
withdraw(&a, 25.00) ? "ok" : "no", a.balance);
return 0;
}The 200 withdrawal must print no and leave the balance unchanged. Confirm that in/c/try.
Several accounts in one array
A bank is more than one person. Store a few records. Print a statement, apply operations by index, print again. Hardcoded amounts keep the output stable.
Example
#include <stdio.h>
struct Account {
char owner[24];
double balance;
};
int deposit(struct Account *a, double amount) {
if (amount <= 0.0) {
return 0;
}
a->balance += amount;
return 1;
}
int withdraw(struct Account *a, double amount) {
if (amount <= 0.0 || amount > a->balance) {
return 0;
}
a->balance -= amount;
return 1;
}
void print_books(const struct Account list[], int n) {
printf("%-8s %8s\n", "owner", "balance");
for (int i = 0; i < n; i++) {
printf("%-8s %8.2f\n", list[i].owner, list[i].balance);
}
}
int main(void) {
struct Account bank[] = {
{"Ada", 100.00},
{"Nia", 15.00},
{"Omar", 250.50},
};
int n = (int)(sizeof bank / sizeof bank[0]);
print_books(bank, n);
deposit(&bank[0], 20.00);
withdraw(&bank[1], 15.00);
withdraw(&bank[1], 1.00);
deposit(&bank[2], -5.00);
printf("after transactions:\n");
print_books(bank, n);
return 0;
}Nia can empty the account with 15, then the extra 1 is refused. Omar’s deposit of -5 is refused. Ada ends at 120.00. Read the second table and check those three facts.
Print a one-line receipt
Callers need a reason when a transfer fails. A thin wrapper can print “deposit refused” or “withdraw refused” without putting printf inside the math helpers. The helpers stay easy to reuse.
Example
#include <stdio.h>
struct Account {
char owner[24];
double balance;
};
int deposit(struct Account *a, double amount) {
if (amount <= 0.0) {
return 0;
}
a->balance += amount;
return 1;
}
int withdraw(struct Account *a, double amount) {
if (amount <= 0.0 || amount > a->balance) {
return 0;
}
a->balance -= amount;
return 1;
}
void try_withdraw(struct Account *a, double amount) {
if (withdraw(a, amount)) {
printf("%s withdrew %.2f; balance %.2f\n", a->owner, amount, a->balance);
} else {
printf("%s cannot withdraw %.2f; balance %.2f\n", a->owner, amount,
a->balance);
}
}
int main(void) {
struct Account a = {"Pia", 50.00};
try_withdraw(&a, 20.00);
try_withdraw(&a, 40.00);
try_withdraw(&a, 0.00);
return 0;
}Common mistakes
- Checking the balance after subtracting. Subtract only when
amount <= a->balance. - Allowing
amount == 0or a negative amount. Treat those as refused, same as overdraft. - Passing the struct by value into
withdraw. Then the copy changes and the caller’s balance stays the same. Pass a pointer. - Comparing money with a long chain of exact fractions. For this project, two decimal places in
printfand simple doubles are enough.
Practice
- Refuse a withdrawal that would leave the balance below 10, as a minimum-reserve rule, and print why.
- Sum every balance in the array and print the bank’s total holdings after the demo transactions.
- Add a transfer helper that withdraws from one account and deposits into another, rolling back if either step fails.