Author : Tom Torfs
Page : << Previous 15 Next >>
}
else
{
ok = 0;
printf("Invalid number! Enter again...\n");
}
}
while (!ok);
if (number_of_persons==0)
{
printf("OK, perhaps another time!\n");
return 0;
}
for (num=0; num<number_of_persons; num++)
{
printf("\nEnter the information for person #%u:\n", num);
printf("Name: ");
fflush(stdout);
if (fgets(buffer, sizeof buffer, stdin) == NULL)
{
printf("Error reading from stdin; input aborted\n");
number_of_persons = num;
break;
}
p = strchr(buffer,'\n');
if (p!=NULL)
*p = '\0';
if (strlen(buffer)==0)
{
printf("Input stopped\n");
number_of_persons = num;
break;
}
strcpy(personlist[num].name, buffer);
do
{
printf("Birthday [YYYY-MM-DD]: ");
fflush(stdout);
if (fgets(buffer, sizeof buffer, stdin) != NULL
&& sscanf(buffer, "%d-%d-%d", &year, &month, &day) == 3
&& year>=1000 && year<=9999
&& month>=1 && month<=12
&& day>=1 && day<=31)
{
ok = 1;
}
else
{
ok = 0;
printf("Invalid birthday! Enter again...\n");
}
}
while (!ok);
personlist[num].birthyear = year;
personlist[num].birthmonth = month;
personlist[num].birthday = day;
}
printf("\nOK, thank you.\n");
printf("\nYou entered the following data:\n");
printf("\n%-10s%-30s%s\n", "Number", "Name", "Birthday");
for (num=0; num<number_of_persons; num++)
{
printf("%-10u%-30s%04d-%02d-%02d\n",
num,
personlist[num].name,
personlist[num].birthyear,
personlist[num].birthmonth,
personlist[num].birthday);
}
free(personlist);
return 0;
}
An example output of this program is:
Enter the number of persons: 10
Enter the information for person #0:
Name: John Doe
Birthday [YYYY-MM-DD]: 70-5-31
Invalid birthday! Enter again...
Birthday [YYYY-MM-DD]: 1970-5-31
Enter the information for person #1:
Name: Foo Bar
Birthday [YYYY-MM-DD]: 1948-1-1
Enter the information for person #2:
Name:
Input stopped
OK, thank you.
You entered the following data:
Number Name Birthday
0 John Doe 1970-05-31
1 Foo Bar 1948-01-01
12.2. Dynamically allocating memory
Well, that seems to be a reasonably complex program, doesn't it ? It's sort of a mini-database, and combines our recently acquired knowledge of structures, strings, pointers and using the standard input/output streams together with a completely new feature: dynamic memory allocation. As usual, we'll explain things step by step:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
As usual, stdio.h is needed for our input/output, and string.h for the string functions we need, like strchr() and strcpy(). However, stdlib.h is also needed because it contains the declarations for the malloc() and free() functions, which we'll use for our dynamic memory allocation.
struct person {char name[30]; /* full name */
unsigned birthday, /* 1..31 */
birthmonth, /* 1..12 */
birthyear; /* 4 digits */
};
As seen in 6. Structs, unions and bit-fields, this is a definition of a structure type. It consists of an array of 30 chars, and 3 unsigned variables. The comments indicate what each member variable will hold:
- the name array will contain the person's full name as a string
- the birthday, birthmonth and birthyear member variables will contain the person's birthdate; the exact values used are documented so that there can be no confusion over the representation of the date
Don't forget that what we've defined here is just a structure type, we don't have any actual variables capable of holding any information yet.
struct person *personlist;
unsigned number_of_persons, num;
char buffer[30];
char *p;
int year, month, day;
int ok;
Now, to hold that information we could have used an array, for example:
struct person personlist[100];
But this way we would limit the number of persons to 100, and someday someone will need more. If we would use a very large number, say 10000, we might seriously reduce the chance of the array being too small, but in most cases we'd also be wasting a lot of space (and it is even possible that your compiler doesn't support very large arrays like that).
How do we solve this problem ? Instead of determining the number of persons in our program's source code, we let the user determine it at runtime, dynamically. That's why we'll need dynamic memory allocation. To be able to do that we must define a pointer (see 10.4. Adresses and pointers) to our type (in this case struct person). This pointer doesn't yet point anywhere valid and no memory is allocated yet, so you shouldn't make the mistake of attempting to use the pointer before any memory has been allocated for it.
That explains the following definition of a pointer to struct person:
struct person *personlist;
The other variable definitions are:
unsigned number_of_persons, num;
char buffer[30];
char *p;
int year, month, day;
int ok;
Here we define two unsigned integers, number_of_persons and num, of which the former will hold - as its name suggests - the number of persons, and the latter will be used as a counter. The buffer array will, as in previous examples, be used to buffer the user's input before processing, and the char pointer will be used to hold the return value of strchr(). The year, month and day variables will be used to temporarily hold a person's birthday, and the ok variable will again be used as a flag variable (1 for ok, 0 for not ok).
do
{
}
while (!ok);
As we've done before, this loop will repeatedly prompt the user for input until the entered data is valid (which will be indicated by setting the flag value ok to 1).
printf("Enter the number of persons: ");
fflush(stdout);
if (fgets(buffer, sizeof buffer, stdin) != NULL
&& sscanf(buffer, "%u", &number_of_persons) == 1)
Page : << Previous 15 Next >>