C string input overflows other string input - c

I'm doing a simple console type command system, and inputting a command will scanf an integer and then will scanf a string, but the contents of the second string overflows the original string
while (exit == 0) {
scanf("%s", input);
if (strcmp(input, "parent") == 0) {
free(input);
ptemp = malloc(sizeof(node_p));
printf("Id: ");
scanf("%d", &ptemp->itemid);
printf("\nElement:");
scanf("%s", ptemp->element);
add_parent_node(parent, ptemp->itemid, ptemp->element);
free(ptemp);
}
}
ptemp is a pointer to a struct containing:
int itemid;
char *element;
I've tried using arrays with predefined size, but nothing seems to work...

Someone that made a comment about nothing overflowing is correct. What you were missing were (in laymans terms) a reservation for characters. Declaring something as char* instead of char[xx] means that you're prepared to reference another part of memory that you're allowed to manipulate with your characters. To keep things simple, I rewritten your code so your program works. Keep in mind that this code relies on users entering strings that are less than 100 to 200 characters long. Feel free to increase the number in square brackets if you need more characters.
I also made an add_parent_node function to verify that the data processing works.
If you want to get a little paranoid and you feel your systems implementation of scanf is screwy, then you can place the following under the while statement:
memset(ptemp,0,sizeof(ptemp));
What that does is floods the entire struct with null characters. This means the value of itemid would be zero since zero is null, and element would be 200 null characters.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int itemid;
char element[200]; //fixed array of chars to actually store a string
}mycollection;
void add_parent_node(char* parentnodename,int itemid,char* element){
printf("Added node as follows\n");
printf("Parent: %s\n",parentnodename);
printf("Item ID: %d\n",itemid);
printf("Element: %s\n\n",element);
}
int main(){
char input[100]; //limit command to 99 characters
mycollection ptemp[1];
while(1){ //while(1) = endless loop
printf("\nEnter command: ");
scanf("%s", input);
if (strcmp(input, "parent") == 0) {
printf("\nId: ");
scanf("%d", &ptemp->itemid);
printf("\nElement:");
scanf("%s", ptemp->element);
add_parent_node("im_the_parent", ptemp->itemid, ptemp->element);
}
if (strcmp(input, "exit") == 0) {
return 0; //return 0 = exit
}
}
}

If you don't want to change anything outside your while loop I think this is what you can do.
while (exit == 0) {
scanf("%s", input);
if (strcmp(input, "parent") == 0) {
if(0 == ptemp ){
/* Allocate memory only once and reuse it.*/
ptemp = malloc(sizeof(node_p));
/* Allocate memory for element. */
ptemp->element = malloc(sizeof(char) * 1024 /* Max string len + 1 */)
}
printf("Id: ");
scanf("%d", &ptemp->itemid);
printf("\nElement:");
scanf("%s", ptemp->element);
add_parent_node(parent, ptemp->itemid, ptemp->element);
}
else if (strcmp(input, "exit") == 0) {
if(0 != ptemp){
/* If memory is allocated for ptemp, free it. */
if(0 != ptemp->element){
free(ptemp->element);
ptemp->element = 0;
}
free(ptemp);
ptemp = 0;
}
free(input);
input = 0;
exit = 1;
break;
}
}

Related

How to store a string that the user inputted into a char pointer instead of a char array

I'm trying to build a program with C but I'm having trouble changing a char array into a char pointer and adjusting the program accordingly. Here's my current code that I want to change:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
char username[20];
char password[20];
char username_input[20];
char password_input[20];
char user_input;
void create_account(char* usrname, char* passwd) {
printf("==================================CREATE BANK ACCOUNT==================================\n");
while(1) {
printf("Enter a username that is less than 20 characters: ");
scanf("%s", usrname);
if (strlen(usrname) <= 20)
break;
printf("That is not less than 20 characters, try again...\n");
sleep(2);
}
while(1) {
printf("Enter a password that is less than 20 characters: ");
scanf("%s", passwd);
if (strlen(passwd) <= 20) {
break;
}
printf("That is not less than 20 characters, try again... \n");
sleep(2);
}
printf("Thank you, please sign in now...\n");
sleep(2);
}
void login() {
while(1) {
printf("Enter Username: ");
scanf("%s", username_input);
printf("Enter Password: ");
scanf("%s", password_input);
if (strcmp(username, username_input) != 0 || strcmp(password, password_input) != 0) {
printf("Incorrect Username or Password. Try again...\n");
sleep(2);
}
else {
printf("Welcome %s\n", username);
sleep(2);
break;
}
}
}
On the lines at the beginning, you can see that there are 4 char array declarations. I want them to be char pointers like so:
char* username;
char* password;
char* username_input;
char* password_input;
The reason for this is because I don't want a limit in a string, but arrays need limits. Once I change that, I want to use malloc() to allocate memory for what the user inputs but I don't know how. In other words, I want to declare a char pointer that accepts user input. And I want enough memory to be allocated for that pointer so that the string that was inputted has enough space. Also I want my code to be compatible with different compilers and computers. For that I'm pretty sure that I have to multiply the malloc() function with sizeof(char) or something like that. I don't necessarily get an error, as in I don't get red lines in my IDE, but the program stops in the middle of it for no reason and gives me an exit code other than 0.
I have done something like this to alloc memory:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
void create_account(char** usrname, char** passwd);
void login(char** usrname, char** passwd, char** input_usrname, char** input_passwd);
void AllocMemory(char*** buf);
int main(){
char* username;
char* password;
char* username_input;
char* password_input;
create_account(&username, &password);
login(&username, &password, &username_input, &password_input);
free(username);
free(password);
free(username_input);
free(password_input);
return 0;
}
void create_account(char** usrname, char** passwd) {
printf("==================================CREATE BANK ACCOUNT==================================\n");
printf("Enter a Username: ");
AllocMemory(&usrname);
printf("Enter a Password: ");
AllocMemory(&passwd);
printf("Thank you, please sign in now...\n");
sleep(2);
}
void login(char** usrname, char** passwd, char** input_usrname, char** input_passwd) {
while(1) {
printf("Enter Username: ");
AllocMemory(&input_usrname);
printf("Enter Password: ");
AllocMemory(&input_passwd);
if (strcmp(*usrname, *input_usrname) != 0 || strcmp(*passwd, *input_passwd) != 0) {
printf("Incorrect Username or Password. Try again...\n");
sleep(2);
}
else {
printf("Welcome %s\n", *usrname);
sleep(2);
break;
}
}
}
void AllocMemory(char*** buf){
int bufSize = 10;
int stringSize;
**buf = calloc(bufSize, sizeof(char));
if(**buf == NULL){
printf("[ERROR] can't malloc %d bytes\n", bufSize);
exit(1);
}
char *readpos = **buf; //point to a pointer of your array!
while(1){ //looping until the alocated memory is enough to the inserted command
do{
fgets(readpos, bufSize, stdin); //reads a line from the specified stream
stringSize = strlen(**buf); //getting the size of the array
if (stringSize == 1)
{
printf("\nYou just pressed enter, pls type again: "); //checking if user just pressed enter
}
}while (stringSize == 1); //looping until user press only enter
if (readpos[strlen(readpos)-1] == '\n'){ //Search from the end as there's where the newline should be if exists, the string fits on array and doesnt need to allocate more memory
readpos[strlen(readpos)-1] = '\0'; //Remove \n from the string
break;
}
**buf = realloc(**buf, bufSize + stringSize * sizeof(char)); // Need to allocate more memory, because the before if its false
if(*buf == NULL){
printf("[ERROR] can't realloc more %d bytes\n", bufSize+1);
exit(1);
}
readpos = **buf + stringSize; // Set the pointer to next position to read into
}
}
I dont know if you are using global variables, but this dont have global variables! But if you want you can use them

Why doesn't my C program wait to scan input?

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 '

C - Segmentation fault when using strlen?

I'm getting a segmentation fault with using strlen.
My function:
void myFunction()
{
int counter = 0;
char * userInput;
bool validInput = true;
while (1)
{
validInput = true;
printf("\nEnter a word: ");
scanf("%s", userInput);
for(counter = 0; counter < strlen(userInput); counter++)
{
if (islower(userInput[counter]) == 0)
{
validInput = false;
break;
}
if (isalpha(userInput[counter]) == 0)
{
validInput = false;
break;
}
}
if (!validInput)
{
printf("Please enter a wordcontaining only lower-case letters.\n");
continue;
}
// Do something
break;
}
}
Is there something wrong with my scanf line? I've never had this sort of issue before with using strlen... so I assume maybe I'm not reading the user's input correctly into 'userInput'.
char * userInput;
The above variable is a pointer , and it is pointing to nowhere (Mean no memory location ) .
It should contain a address to store / retrieve data .
So either you must allocate memory for this variable or use strdup
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
char *inputStr; //wrong.
char inputStrArray[100]; //correct
char *inputStrPtr = malloc(sizeof(char)*100) ;//OK but dont forget to free the memory after use
int condition = 1;
while(condition )
{
printf("Please enter a string :");
//scanf("%s",&inputStr); //wrong
//printf(inputStr);
scanf("%s",inputStrArray);
printf("Ok I got it %s \n",inputStrArray);
printf("Please enter one more time a string: ");
scanf("%s",inputStrPtr);
printf("Now I got it %s \n",inputStrPtr);
condition = 0;
}
free(inputStrPtr);
inputStrPtr = NULL; //try not to use it anywhere else
return 0;
}
Use char userInput[128]; instead.
scanf expects a pointer to valid memory to put the contents of the users input in to.

strtok() then strcmp() returning false when true

I'm guessing this is a type issue, so maybe you can show me how it is correctly done.
I'm reading command inputs from stdin and I want to quit when the user enters q.
I'm reading a user input from stdin using fgets() into a pointer to a character array. Then I splice off the first word using strtok() and assign it to another pointer to a character array. Then I compare it to a q in order to see if the user wants to quit the program by using the strcmp() function.
Here is some code:
char *input = (char*)malloc(32 * sizeof(char));
char *command = (char*)malloc(8 * sizeof(char));
while (strcmp(command, "q") != 0)
{
memset(input, 0, sizeof(input));
printf("Enter command: ");
fgets(input, 64, stdin);
command = strtok(input, " ");
//if I enter q --> printf("%d", strcmp(command, "q")) == 10
//if I enter w --> printf("%d", strcmp(command, "q")) == 6
}
What I want is, if command == q then printf("%d", strcmp(command, "q")) should equal 0 else it should print any other integer.
I should also note that I have verified command is being correctly assigned. In other words, when I enter q, command == "q".
Maybe you can try this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *input = (char*)malloc(32 * sizeof(char));
char *command = (char*)malloc(8 * sizeof(char));
while (strcmp(command, "q") != 0)
{
memset(input, 0, sizeof(input));
printf("Enter command: ");
fgets(input, 64, stdin);
command = strtok(input, " \n"); // Line corrected.
//if I enter q --> printf("%d", strcmp(command, "q")) == 10
//if I enter w --> printf("%d", strcmp(command, "q")) == 6
}
return 0;
}
Several issues here.
The memory allocated here
char *command = (char*)malloc(8 * sizeof(char));
leaks the moment this line
command = strtok(input, " ");
gets execute as the one and only reference to the memory allocated gets overwritten and therefore lost.
A possible buffer overflow can occur here
fgets(input, 64, stdin);
as allowing to read more bytes (64) ito input as it points to be the allocation done here
char *input = (char*)malloc(32 * sizeof(char));
Assuming the data input by the user does not contain a sequence like '[blanks]q ...thencommandget assignedNULL` by this call
command = strtok(input, " ");
which leads to passing NULL to strcmp() here on testing for next iteration here
while (strcmp(command, "q") != 0)
Doing so invoke undefined behaviour.
The code misses to check the outcome of relevant function calls, like malloc()`` andfgets()`.
Casting the result of malloc() & friends isn't needed in C nor is it recommended in way. So just do not do it. It might very well hide errors.
sizeof (char) is defined to be 1. No need to use it.
Do not spoil you code with "Magic Numbers"/"Tokens" like 32, 8, 64, "q" ...
Using while-loop conceptionally is the wrong approach if you want to perform a certain action at least once. In such cases use a do-while loop.
Fixing all this might lead to the following code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define INPUT_BUFFER_SIZE (64)
#define QUIT_STRING "q"
int main(void)
{
int result = EXIT_SUCCESS; /* Be optimistic. */
char *input = malloc(INPUT_BUFFER_SIZE * sizeof *input);
if (NULL == input)
{
perror("malloc () failed");
result = EXIT_FAILURE;
}
else
{
char *command;
do
{
printf("Enter command:\n");
if (NULL == fgets(input, INPUT_BUFFER_SIZE, stdin))
{
if (!feof(stdin))
{
result = EXIT_FAILURE;
fprintf(stderr, "fgets() failed.\n");
}
break;
}
command = strtok(input, " \n");
} while ((command == NULL) || strcmp(command, QUIT_STRING) != 0);
if (NULL != command)
{
printf("User quit.\n");
}
free(input);
}
return result;
}

Why is my file output overwritten?

My program takes user input and stores it in an array of Records that I've defined as a structure: struct Record.
The user input is are the fields of the struct. Everything complies error free, but it seems I can't get the formatting correct. My program keeps asking for user input until the user enters 'n' when asked if there are anymore records.
Once there are no more records the program loops through the created records and file prints each of them spaced out by tabs and at the end starting with a newline for the next record. However, instead of starting at a new line and printing another record in the same fashion, it overwrites the previous record printed and tabs the next one even further.
What causes this to happen?
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
char zipcode[51];
char phoneNumber[51];
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = 'y';
int size = 1;
int i = 0;
struct Record *records;
struct Record *records_temp = NULL;
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = calloc((size),sizeof(*records));
records = records_temp;
printf("First Name: \n");
scanf("%s", records[size-1].fname);
printf("Last Name: \n");
scanf("%s", records[size-1].lname);
printf("Address: \n");
scanf(" %[^\n]", records[size-1].address);
printf("City: \n");
scanf("%s", records[size-1].city);
printf("State: \n");
scanf("%s", records[size-1].state);
printf("Zipcode: \n");
scanf("%s", records[size-1].zipcode);
printf("Phone Number: \n");
scanf("%s", records[size-1].phoneNumber);
//stores all record info
printf("Are there anymore records? [y/n] ");
scanf(" %c", &answer);
if(answer == 'y' || answer == 'Y')
{
size++;
printf("\n");
}
}
//open file
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL)
{
for(;i< size; i++)
{
fprintf(fileWriter,"%s\t",records[i].fname);
fprintf(fileWriter,"%s\t",records[i].lname);
fprintf(fileWriter,"%s\t",records[i].address);
fprintf(fileWriter,"%s\t",records[i].city);
fprintf(fileWriter,"%s\t",records[i].state);
fprintf(fileWriter,"%s\t",records[i].zipcode);
fprintf(fileWriter,"%s\n",records[i].phoneNumber);
}
free(records);
fclose(fileWriter);
}
else
{
printf("Error opening file.");
}
}
I changed a little bit your code, but I think you should use linked list as a data structure here, it's more simple and consume less memory.
I made some tries and all went ok. :)
Hope that help you!!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct Record Record;
struct Record
{
char fname[51];
char lname[51];
char address[51];
char city[51];
char state[51];
char zipcode[51];
char phoneNumber[51];
Record *next;
};
int main()
{
FILE *fileWriter;
const char filename[] = "data.txt";
char answer = '\0';
// int size = 1;
// int i = 0;
Record *records = NULL;
Record *records_first = NULL;
Record *records_previous = NULL;
fileWriter = fopen(filename,"wb");
if(fileWriter != NULL) {
for( ; ; ) {
records = (Record*) malloc(sizeof(Record));
if(records_first == NULL)
records_first = records;
if(records_previous != NULL)
records_previous->next = records;
records = records_first;
printf("First Name: \n");
scanf("%s", records->fname);
fprintf(fileWriter,"%s\t",records->fname);
printf("Last Name: \n");
scanf("%s", records->lname);
fprintf(fileWriter,"%s\t",records->lname);
printf("Address: \n");
scanf(" %[^\n]", records->address);
fprintf(fileWriter,"%s\t",records->address);
printf("City: \n");
scanf("%s", records->city);
fprintf(fileWriter,"%s\t",records->city);
printf("State: \n");
scanf("%s", records->state);
fprintf(fileWriter,"%s\t",records->state);
printf("Zipcode: \n");
scanf("%s", records->zipcode);
fprintf(fileWriter,"%s\t",records->zipcode);
printf("Phone Number: \n");
scanf("%s", records->phoneNumber);
fprintf(fileWriter,"%s\t\n\n",records->phoneNumber);
records->next = NULL;
records_previous = records;
printf("Are there anymore records? [y/n] ");
scanf(" %c", &answer);
if(tolower(answer) != 'y') {
free(records);
fclose(fileWriter);
break;
}
}
} else
printf("Error opening file.");
return 0;
}
Open the file with additional a mode as in "append". I think there is no need for further explanation what that would be good for, right?
However, the actual problem seems that you overwrite the pointer to the previous record already in the input loop. How is that supposed to work? Just go through that loop and try to follow the instructions as the program would do.
Problem is you cannot do it like this. Use a linked list for the allocated blocks.
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = calloc((size),sizeof(*records));
records = records_temp;
...
}
Did you perhaps mean this?
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = realloc(records, size * sizeof *records);
if (records_temp == NULL)
{
/* Handle allocation error */
}
records = records_temp;
/* ... */
}
Do not confuse calloc with realloc. Read the manuals if you need further clarification.
Don't forget to initialise records to NULL...
If your concern is optimisation, the most significant bottleneck here will be your file input/output. That's unavoidable, and aside from researching setvbuf there isn't much you can do about it. The next bottleneck will be underlying calls to kernel allocation functions. You can reduce that bottleneck by calling allocation functions less. For example, you could grow your array by doubling its size each time rather than by adding 1:
size_t size = 0;
int answer;
do {
size_t index = size++;
if ((index & size) == 0) {
void *temp = realloc(array, (2 * index + 1) * sizeof *array);
if (temp == NULL) {
/* Handle allocation error */
}
array = temp;
}
puts("First Name:");
scanf("%s", array[index].fname);
/* snip */
answer = getchar();
} while (answer != EOF && tolower(answer) == 'y');
Alternatively, you could reinvent the wheel and perform the same work that realloc performs behind the scenes (and possibly lose some benefit of optimisation), by adding calls to memcpy and free to your code like so:
while(answer == 'y' || answer == 'Y')
{
struct Record *records_temp = calloc((size),sizeof(*records));
if (records_temp == NULL)
{
/* Handle allocation error */
}
if (records != NULL)
{
memcpy(records_temp, records, (size - 1) * sizeof *records);
free(records);
}
records = records_temp;
/* ... */
}
P.S. In case you missed it the first time: Don't forget to initialise records to NULL...
The biggest problem I see is memory allocation logic. The first time through the loop, you allocate memory for 1 record and increment size. The second time through the loop, you allocate memory for 2 more records, because size == 2. The third time through the loop, you allocate memory for 3 more records, for a total of 1+2+3=6.
That answers why it's happening. Olaf's suggested fix, linked list, is a good one.

Resources