I am new to C. I allocated memory with this statement:
patientptr = (char*) calloc (118, sizeof (char));
then I assign data using this (this is a part of the function):
char name[51];
int age;
char agestr[3];
char infectiondate [11];
char address[51];
char *patientptr;
printf("\nEnter the patient name (50 characters at maximum): ");
scanf ("%50s", name);
*patientptr = name;
printf("Enter the patient age: ");
scanf ("%d", &age);
sprintf (agestr, "%2d", age);
*(patientptr + 51) = agestr;
printf("Enter the patient date of infection (in form of dd/mm/year): ");
*(patientptr + 54) = scanf ("%10d", infectiondate);
printf("Enter the patient address (50 characters at maximum): ");
*(patientptr + 65) = scanf ("%50s", address);
*(ptrsptr+patientsnum-1) = patientptr;
printf ("\nPatient added.\n");
Everything goes fine except that after the "enter the patient address: " line, it prints the "patient added" line directly without waiting to scan the address. the output is like this:
Enter the patient name (50 characters at maximum): ahmed
Enter the patient age: 20
Enter the patient date of infection (in form of dd/mm/year): 10/10/2020
Enter the patient address (50 characters at maximum):
Patient added.
is the wrong with my allocated memory?
You may well have used calloc
to allocate some memory but examine this snippet:
char *patientptr;
printf("\nEnter the patient name (50 characters at maximum): ");
scanf ("%50s", name);
*patientptr = name;
That first line shadows whatever patientptr
was with an uninitialised pointer, hence the final line is undefined behaviour ( patientptr
now points to some arbitrary address). All bets are off at this point, anything is possible.
Fix that and try again.
In addition, it looks like you believe that:
*(patientptr + 51) = agestr;
is a way to copy a C string from one place to another. In actual fact, this will attempt to place the agestr
pointer value into the single character at the memory location &(patientptr[51])
, and possibly should have warned you about this.
You need to look into strcpy
for this, something along the lines of:
strcpy(patientptr + 51, agestr);
But, if you're looking to do user input, it's often a good idea to work around the limits of scanf
. It does, after all, stand for "scan formatted" and there's very little that's less formatted than user input.
I have a favourite function I use for this, which is shown below, along with the modifications to your own code to use it (using both that function and with quite a bit of other validation specific to your case):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
// Bullet-proof line input function.
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
// Ensure a character array is non-empty and all digits.
int checkDigits(char *arr, size_t sz) {
if (sz == 0) {
return 0;
}
while (sz-- > 0) {
if (! isdigit(*arr++)) {
return 0;
}
}
return 1;
}
// Get customer data line, return NULL if okay, error if not.
// Output record must be long enough for format string below
// and a one-character end-string marker.
static char *getPatientData(char *patientData) {
// Keep this format string in sync with field sizes below.
static char *fmtString = "%-50.50s" "%3d" "%-10.10s" "%-50.50s";
char name[51];
char ageStr[4];
char infectionDate[11];
char address[51];
if (getLine("Patient name: ", name, sizeof(name)) != OK) {
return "Error getting name.";
}
if (getLine("Patient age: ", ageStr, sizeof(ageStr)) != OK) {
return "Error getting age.";
}
if (! checkDigits(ageStr, strlen(ageStr))) {
return "Error, age contains non-digit data.";
}
int age = atoi(ageStr);
// Further age sanity checking, if desired. Example: ensure <= 150.
if (getLine("Infection date (dd/mm/yyyy): ", infectionDate, sizeof(infectionDate)) != OK) {
return "Error getting infection date.";
}
if (
strlen(infectionDate) != 10
|| infectionDate[2] != '/'
|| infectionDate[5] != '/'
|| ! checkDigits(infectionDate, 2)
|| ! checkDigits(infectionDate + 3, 2)
|| ! checkDigits(infectionDate + 6, 4)
) {
return "Error, incorrect format.";
}
// Further checking if desired. Example: valid year/month/day combo.
if (getLine("Patient address: ", address, sizeof(address)) != OK) {
return "Error getting address.";
}
sprintf(patientData, fmtString, name, age, infectionDate, address);
return NULL;
}
int main(void) {
char *patientPtr = malloc (50 + 3 + 10 + 50 + 1);
char *result = getPatientData(patientPtr);
if (result != NULL) {
printf("*** %s\n", result);
return 1;
}
printf("Got '%s'\n", patientPtr);
return 0;
}
A sample run follows:
Patient name: Pax Diablo
Patient age: 55
Infection date (dd/mm/yyyy): 25/05/2020
Patient address: No fixed abode
Got 'Pax Diablo 5525/05/2020No fixed abode '
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.