Reallocation problems when assigning string to dynamic int array - c

Basically, I'm trying to convert a bunch of char inputs to ints and assign them to a dynamic int array. The string input and tokenization seem to work fine. The issue (from what I can tell) seems to be with the reallocation of the int array; after the array is reallocated twice, the pointer to the int array returns NULL.
What I tried to do was double the size of the int array every time the number of tokens meets or surpasses (size divided by sizeof(int)). The realloc statement works each time this condition is met.
I thought using a pointer to a pointer was the end-all solution to this. I bet it's some really obvious issue, but I'm at my wit's end here. If you request any further elaboration, I'll try my best. Understand that I've only taken C for a semester and have struggled most of the way.
Also, truth be told, this was part of a class assignment which has since passed. I'd prefer an explanation about what's wrong more than a full-on code, if that's alright.
I have a lot of printf statements, so apologies for any clutter.
EDIT: Replaced all instances of newArray within the input() function with *resize. However, I've never tried assigning values through pointers to pointers, so feel free to correct me with a syntactic example if you know how I messed up. Segmentation fault occurs here:
for (k = (numElem - count); k < numElem; k++)
{
printf("\nk = %i\n", k);
printf("j = %i\n", j);
printf("numElem = %i\n", numElem);
printf("results[j]: %s\n\n\n", results[j]);
/* Segmentation fault regardless of what is assigned
to *resize[k]. */
*resize[k] = atoi(results[j]); // PROBLEM HERE
j++;
}
The source code has been updated to reflect upon this. To make this ridiculously long post a little more subdued, let's state that I did this in main():
int *newArray = malloc(MAXTOKEN * sizeof(int));
input(&newArray);
free(newArray);
Moving on.
/* String input takes in char values,
tokenizes them, converts the results
to int, assigns them to newresizeay. */
int input(int **resize)
{
int i, j, k, count;
int numElem = 0;
int currentSize = MAXTOKEN;
char str[MAXSTRING];
char *results[MAXTOKEN];
/* This entire loop takes place at least once,
provided the first input isn't NULL. */
do
{
i = 0, j = 0, k = 0;
/* Char input process. Takes place until the user
presses ENTER. */
printf("Input integer values separated by spaces, or "
"press ENTER to exit.\n");
while ( ((str[i] = getchar() ) != '\n') && (i < MAXSTRING) )
i++;
printf("\n\n");
str[i] = '\0';
/* Tokenization of the chars that were input */
count = 0;
if (results[0] = strtok(str, " \t"))
count++;
while (results[count] = strtok(NULL, " \t") )
count++;
/* numElem = 1 if the first input prompt established
str[0] as NULL */
if ( (count < 1) && (numElem < 1) )
count = 1;
numElem += count;
printf("numElem: %i\ncurrentSize: %i\n", numElem, currentSize);
/* If the number of elements to assign meet or surpass
the amount of [memory / sizeof(int)], exponentially
increase the size of the int resizeay. */
if ( numElem >= currentSize )
{
*resize = realloc(*resize, (currentSize) * sizeof(int));
if (*resize == NULL)
printf("\n\nYep, it threw up.\n\n");
currentSize *= 2;
}
printf("\nSize should be: %i\n", currentSize * 4);
printf("Actual size: %d\n", _msize(*resize));
/* The tokenized chars are converted to integers and
assigned to the int resizeay. */
for (k = (numElem - count); k < numElem; k++)
{
printf("\nk = %i\n", k);
printf("j = %i\n", j);
printf("numElem = %i\n", numElem);
printf("results[j]: %s\n\n\n", results[j]);
*resize[k] = atoi(results[j]); // PROBLEM HERE
j++;
}
for (i = 0; i < numElem; i++)
printf("resize[%i]: %i\n", i, *resize[i]);
printf("\n\n\n");
} while (str[0] != NULL);
}

The input function receives both resize and arr. main sends the same pointer to both. This is a bug.
When resize is resized, arr stays the same and may point to an invalid address (when realloc returns a different address).
How to fix:
Remove arr function argument and only use resize.

When you call the realloc function,if the new memory block is smaller than previous ,it will maintain the original state pointing to the memory block which previous used.If the new memory block is larger than previous,the system will re allocate memory on the heap and the previous memory is released.

Among other problems:
char *results[MAXTOKEN];
should be
char *results[MAXTOKEN + 1];
because here the maximum value of count will be MAXTOKEN in this loop :
while (results[count] = strtok(NULL, " \t") )
count++;
and
char str[MAXSTRING];
is pretty scary, because as soon as the user enters more than MAXSTRIN (=11) characters without pressing Enter, you will get a buffer overflow.

Related

HEAP CORRUPTION DETECTED: after normal block(#87)

I'm trying to do a program that get number of names from the user, then it get the names from the user and save them in array in strings. After it, it sort the names in the array by abc and then print the names ordered. The program work good, but the problem is when I try to free the dynamic memory I defined.
Here is the code:
#include <stdio.h>
#include <string.h>
#define STR_LEN 51
void myFgets(char str[], int n);
void sortString(char** arr, int numberOfStrings);
int main(void)
{
int i = 0, numberOfFriends = 0, sizeOfMemory = 0;
char name[STR_LEN] = { 0 };
char** arrOfNames = (char*)malloc(sizeof(int) * sizeOfMemory);
printf("Enter number of friends: ");
scanf("%d", &numberOfFriends);
getchar();
for (i = 0; i < numberOfFriends; i++) // In this loop we save the names into the array.
{
printf("Enter name of friend %d: ", i + 1);
myFgets(name, STR_LEN); // Get the name from the user.
sizeOfMemory += 1;
arrOfNames = (char*)realloc(arrOfNames, sizeof(int) * sizeOfMemory); // Change the size of the memory to more place to pointer from the last time.
arrOfNames[i] = (char*)malloc(sizeof(char) * strlen(name) + 1); // Set dynamic size to the name.
*(arrOfNames[i]) = '\0'; // We remove the string in the currnet name.
strncat(arrOfNames[i], name, strlen(name) + 1); // Then, we save the name of the user into the string.
}
sortString(arrOfNames, numberOfFriends); // We use this function to sort the array.
for (i = 0; i < numberOfFriends; i++)
{
printf("Friend %d: %s\n", i + 1, arrOfNames[i]);
}
for (i = 0; i < numberOfFriends; i++)
{
free(arrOfNames[i]);
}
free(arrOfNames);
getchar();
return 0;
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char str[], int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
/*In this function we get array of strings and sort the array by abc.
Input: The array and the long.
Output: None*/
void sortString(char** arr, int numberOfStrings)
{
int i = 0, x = 0;
char tmp[STR_LEN] = { 0 };
for (i = 0; i < numberOfStrings; i++) // In this loop we run on all the indexes of the array. From the first string to the last.
{
for (x = i + 1; x < numberOfStrings; x++) // In this loop we run on the next indexes and check if is there smaller string than the currnet.
{
if (strcmp(arr[i], arr[x]) > 0) // If the original string is bigger than the currnet string.
{
strncat(tmp, arr[i], strlen(arr[i])); // Save the original string to temp string.
// Switch between the orginal to the smaller string.
arr[i][0] = '\0';
strncat(arr[i], arr[x], strlen(arr[x]));
arr[x][0] = '\0';
strncat(arr[x], tmp, strlen(tmp));
tmp[0] = '\0';
}
}
}
}
After the print of the names, when I want to free the names and the array, in the first try to free, I get an error of: "HEAP CORRUPTION DETECTED: after normal block(#87)". By the way, I get this error only when I enter 4 or more players. If I enter 3 or less players, the program work properly.
Why does that happen and what I should do to fix it?
First of all remove the unnecessary (and partly wrong) casts of the return value of malloc and realloc. In other words: replace (char*)malloc(... with malloc(..., and the same for realloc.
Then there is a big problem here: realloc(arrOfNames, sizeof(int) * sizeOfMemory) : you want to allocate an array of pointers not an array of int and the size of a pointer may or may not be the same as the size of an int. You need sizeof(char**) or rather the less error prone sizeof(*arrOfNames) here.
Furthermore this in too convoluted (but not actually wrong):
*(arrOfNames[i]) = '\0';
strncat(arrOfNames[i], name, strlen(name) + 1);
instead you can simply use this:
strcpy(arrOfNames[i], name);
Same thing in the sort function.
Keep your code simple.
But actually there are more problems in your sort function. You naively swap the contents of the strings (which by the way is inefficient), but the real problem is that if you copy a longer string, say "Walter" into a shorter one, say "Joe", you'll write beyond the end of the allocated memory for "Joe".
Instead of swapping the content of the strings just swap the pointers.
I suggest you take a pencil and a piece of paper and draw the pointers and the memory they point to.

C: realloc works on Linux, but not on Windows

this is my first question on Stack Overflow, sorry if it's not well written.
I have a little problem. I wrote a program in C (I'm currently learning C, I am a newbie, my first language, don't say I should've learnt Python, please, because I'm doing just fine with C). So, I wrote this little program. It's an attempt of mine to implement a sorting algorithm (I made the algorithm myself, with no help or documentation, it's very inefficient I think, I was just fooling around, though I don't know whether the algorithm already exists or not). The only sorting algorithm I know is QuickSort.
In any case, here is the final program (has plenty of comments, to help me remember how it works if I'll ever revisit it):
// trying to implement my own sorting algorithm
// it works the following way:
// for an array of n integers, find the largest number,
// take it out of the array by deleting it, store it
// at the very end of the sorted array.
// Repeat until the original array is empty.
// If you need the original array, simply
// make a copy of it before sorting
/***************************************/
// second implementation
// same sorting algorithm
// main difference: the program automatically
// computes the number of numbers the user enters
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int *sort(int *a, int n); // sort: the actual sorting function
char *read_line(char *str,int *num_of_chars); // read_line: reads input in string form
int *create_array(char *str, int n); // create_array: counts the num of integers entered and extracts them
// from the string the read_line function returns, forming an array
int size_of_array_to_be_sorted = 0; // of integers
int main(void)
{
int *array, i, *sorted_array, size = 3;
char *str = malloc(size + 1);
if (str == NULL)
{
printf("\nERROR: malloc failed for str.\nTerminating.\n");
exit(EXIT_FAILURE);
}
printf("Enter the numbers to be sorted: ");
str = read_line(str, &size);
array = create_array(str, size + 1);
sorted_array = sort(array, size_of_array_to_be_sorted);
printf("Sorted: ");
for (i = 0; i < size_of_array_to_be_sorted; i++)
printf("%d ", sorted_array[i]);
printf("\n\n");
return 0;
}
int *sort(int *a, int n)
{
int i, j, *p, *sorted_array, current_max;
sorted_array = malloc(n * (sizeof(int)));
if (sorted_array == NULL)
{
printf("ERROR: malloc failed in sort function.\nTerminating.\n");
exit(EXIT_FAILURE);
}
for (i = n - 1; i >= 0; i--) // repeat algorithm n times
{
current_max = a[0]; // intiliaze current_max with the first number in the array
p = a;
for (j = 0; j < n; j++) // find the largest integer int the array
if (current_max < a[j])
{
current_max = a[j];
p = (a + j); // make p point to the largest value found
}
*p = INT_MIN; // delete the largest value from the array
sorted_array[i] = current_max; // store the largest value at the end of the sorted_array
}
return sorted_array;
}
char *read_line(char *str, int *num_of_chars)
{
int i = 0; // num of chars initially
char ch, *str1 = str;
while ((ch = getchar()) != '\n')
{
str1[i++] = ch;
if (i == *num_of_chars) // gives str the possibility to
{ // dinamically increase size if needed
str1 = realloc(str, (*num_of_chars)++);
if (str1 == NULL)
{
printf("\nERROR: realloc failed in read_line.\nTerminating.\n");
exit(EXIT_FAILURE);
}
}
}
// at the end of the loop, str1 will contain the whole line
// of input, except for the new-line char. '\n' will be stored in ch
str1[i++] = ch;
str1[i] = '\0'; // store the null char at the end of the string
return str1;
}
int *create_array(char *str, int n)
{
int *array, i, j, k, num_of_ints = 0;
for (i = 0; i < n; i++) // computing number of numbers entered
if (str[i] == ' ' || str[i] == '\n')
num_of_ints++;
array = calloc((size_t) num_of_ints, sizeof(int)); // allocacting necessary space for the array
if (array == NULL)
{
printf("\nERROR: calloc failed in create_array.\nTerminating.\n");
exit(EXIT_FAILURE);
}
k = 0;
i = 1; // populating the array
for (j = n - 1; j >= 0; j--)
{
switch (str[j])
{
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': array[k] += ((str[j] - '0') * i);
i *= 10;
break;
case '-': array[k] = -array[k]; // added to support negative integers
default: i = 1;
if (str[j] == ' ' && (str[j - 1] >= '0' && str[j - 1] <= '9'))
/* only increment k
*right before a new integer
*/
k++;
break;
}
}
// the loop works in this way:
// it reads the str string from the end
// if it finds a digit, it will try to extract it from the
// string and store in array, by adding to one of the elements
// of array the current char - ASCII for '0', so that it actually gets a digit,
// times the position of that digit in the number,
// constructing the number in base 10: units have 1, decimals 10, hundreds 100, and so on
// when it finds a char that's not a digit, it must be a space, so it resets i
// and increments k, to construct a new number in the next element of array
size_of_array_to_be_sorted = num_of_ints;
return array;
}
I've written everything myself, so if you think I use some bad methods or naive approaches or something, please tell me, in order for me to be able to correct them. Anyways, my problem is that I have these 'try to handle errors' if statements, after every call of malloc, calloc or realloc. I have a Linux machine and a Windows one. I wrote the program on the Linux one, which has 4GB of RAM. I wrote it, compiled with gcc, had to change a few things in order to make it work, and it runs flawlessly. I have no problem. I then copied it onto a USB drive and compiled it with mingw on my Windows machine, which has 8GB of RAM. I run it, and if I give it more than 3 2-digit integers, it displays
ERROR: realloc failed in read_line.
Terminating.
At least I know that the 'error handling' if statements work, but why does this happen? It's the same code, the machine has twice as much RAM, with most of it free, and it runs with no problem on Linux.
Does this mean that my code is not portable?
Is it something I don't do right?
Is the algorithm wrong?
Is the program very, very inefficient?
Sorry for the long question.
Thanks if you wanna answer it.
The line in question is:
str1 = realloc(str, (*num_of_chars)++);
where *num_of_chars is the current size of str. Because you are using post-increment, the value passed for the new allocation is the same as the current one, so you haven't made str any bigger, but go ahead and act as if you had.

Dynamically allocating a 2D array in C

I've been reading around and I've been applying what I've been reading to my code but I am not sure if I am missing something.. the 2d array is suppose to mirror sudoku.
I know the problem area is in my arrayMake function.
My professor recommended using a cast with the malloc call so:
sudoku = (int**)malloc(sudokus*sizeof(int*)); but that did not work for me.
int main(){
int sudokus;
int** sudoku;
sudokus = getUserInfo();
sudoku = arrayMake(sudokus);
/*for (int i = 0; i < (SIZE*sudokus), i++;){
for (int j = 0; j < SIZE, j++;){
printf("Numbers[%d][%d]:%d", i, j, sudoku[i][j]);
}
}*/
system("pause");
return 0;
}
int getUserInfo(){
int sudokus;
printf("How many Sudokus are you checking today?\n");
scanf("%d{^\n]\n", &sudokus);
return sudokus;
}
int** arrayMake(int sudokus){
int **sudoku;
int realsize;
realsize = 9 * sudokus;
sudoku = malloc(realsize*sizeof(int*));
if (sudoku == NULL){
printf("Memory allocation failed");
return 0;
}
for (int i = 0; i < realsize, i++;){
sudoku[i] = malloc(9 * sizeof(int));
if (sudoku[i] == NULL){
printf("Memory allocaiton failed");
return 0;
}
}
return sudoku;
}
My professor recommended using a cast with the malloc call so: sudoku = (int**)malloc(sudokus * sizeof(int*)); but that did not work for me.
To dynamically allocate for 2D array, you usually need to do two steps. Your code is not clear as you include a realsize = 9 * sudokus which doesn't make sense. Anyway, for simplicity, lets assume your sudoku is a 3x3 matrix. You'll need to:
Allocate for the pointer to pointer to int:
int **sudoku = malloc( 3 * sizeof( int * ) );
Allocate for each of the individual pointer to int:
for( int i = 0; i < 3; i++ )
sudoku[i] = malloc( 3 * sizeof( int ) );
From what I see your problem exists in your for loops where you have:
for (i = 0;i < realsize , i++)
when you really meant:
for (i = 0;i < realsize ; i++)
^
Note the change of , to ;
scanf("%d{^\n]\n", &sudokus); is a mistake.
I guess you meant the { to actually be a [ but the format string is still wrong even after that change. I think you intended to consume the rest of the input, up to and including a newline character. However, your format string does not actually do that.
Scanf'ing for \n actually means consume any amount of whitespace, so in fact this code (with the [ fix) would continue waiting for input until there was a newline, and also another non-whitespace character typed after the newline.
Better would be:
scanf("%d", &sudokus);
int ch;
while ( (ch = getchar()) != '\n' && ch != EOF ) { }
There are a few different ways to achieve the same goal. (Note that scanning for %d[^\n]%c is not one of them; that string is also broken).
Also I would suggest a different variable name than sudokus. It's confusing having two similarly-named variables sudoku and sudokus. Name it something that reflects its meaning.
For allocating your array, it would be much simpler to take out the arrayMake function and write something like:
int sudoku[9][9];
(I couldn't figure out what sudokus was supposed to mean or what realsize was going to be, but you could put your intended dimension inside the square brackets there).

Reallocation of Multi-dimensonal Pointer Array Causing Segmentation Fault

First, I'll explain why I'm doing this the way that I am. I'm taking a course in computer programming and my professor has given us an assignment where we have to make an array of records(each contains a first name, last name, & score), and then allow the user to manipulate the records using menu options. All of this MUST be done using only pointer arrays, and structures are not allowed. I know it is a headache. I know it probably one of the most difficult ways to accomplish this, but its what the professor wants.
With that out of the way, below is what I have for my main function so far. most of the long printf functions are just me printing debugging information. Please take note of the declaration of the char*** variable. It is meant to function as a 3D array where nameRecords[0] would be the first record, nameRecords[0][0] would be the first name of the first record, and nameRecords[0][1] is the last name of the first record. The third dimension is nameRecords[0][0][21], as the strings are only meant to be 20 characters long plus null character.
int main(void)
{
char ***nameRecords = NULL;
float *scores = NULL;
int size = 0; // total number of records
int usrInt = 0;
while(usrInt < 1)
{
printf("\nEnter the number of records to record(min 1): ");
scanf("%d", &usrInt);
inpurge();
if(usrInt < 1) printf("\nMust be integer greater than 1.\n");
}
nameRecords = (char***)calloc((size), sizeof(char**));
scores = (float*)calloc(size, sizeof(float));
int i;
for(i = 0; i < usrInt; i++)
{
addRecord(&nameRecords, &scores, &size);
printf("\nnameRecords#%p :: nameRecords[%d]#%p :: nameRecords[%d][0]=%s :: nameRecords[%d][1]=%s\n", nameRecords, size - 1, nameRecords[size - 1], size - 1, nameRecords[size - 1][0], size - 1, nameRecords[size - 1][1]);
}
printf("\nnameRecords[0]#%p\n", nameRecords[0]);
prntRecords(nameRecords, scores, size);
printf("\n\n\n");
return 0;
}
The trouble comes after I pass, for the SECOND TIME, &nameRecords into the addRecord function, defined below. To clarify, the segmentation fault is not received if the user chooses to enter only 1 entry at the beginning of the main function, and the program actually runs and terminates as expected.
void addRecord(char ****records, float **scores, int *size)
{
printf("\t(*records)[0]%p\n", (*records)[0]);
++*size; // increment total number of records by 1
int index = (*size) - 1;
char ***tempNames = (char***)realloc(*records, (*size) * sizeof(char**)); // reallocate larger space.
if(tempNames != *records)
*records = tempNames; // set original pointer to new value.
printf("\n\tsize - 1 = %d\n", index);
float *tempScores = (float*)realloc(*scores, (*size) * sizeof(float)); // reallocate larger space.
if(tempScores != *scores)
*scores = tempScores; // set original pointer to new value.
printf("\ttempNames[0]#%p\n", tempNames[0]);
tempNames[index] = (char**)calloc(tempNames[index], 2 * sizeof(char*));
enterRecord(tempNames[index], scores[index]);
printf("\n\ttempNames#%p :: tempNames[0]#%p :: tempNames[%d][0]=%s :: tempNames[%d][1]=%s\n", tempNames, tempNames[0], index, tempNames[index][0], index, tempNames[index][1]);
printf("\n\t*records#%p :: *records[0]#%p :: *records[%d][0]=%s :: *records[%d][1]=%s\n", *records, (*records)[0], index, (*records)[index][0], index, (*records)[index][1]);
return;
}
Below is an example output of the program. Without taking too long to explain whats happening, the tabbed lines are the lines of output from within the addRecord function. Specifically, the pointer to the first record, record[0], has been turned into a garbage value on the second pass through the addRecord function, just after the enterRecord function.
Enter the number of records to record(min 5): 2
(*records)[0](nil)
size - 1 = 0
tempNames[0]#(nil)
Enter first name: 1
Enter last name: 1
Enter score: 1
COMPLETE enterRecord
tempNames#0x6387010 :: tempNames[0]#0x6387050 :: tempNames[0][0]=1 :: tempNames[0][1]=1
*records#0x6387010 :: *records[0]#0x6387050 :: *records[0][0]=1 :: *records[0][1]=1
nameRecords#0x6387010 :: nameRecords[0]#0x6387050 :: nameRecords[0][0]=1 :: nameRecords[0][1]=1
(*records)[0]0x6387050
size - 1 = 1
tempNames[0]#0x6387050
Enter first name: 2
Enter last name: 2
Enter score: 2
COMPLETE enterRecord
tempNames#0x6387010 :: tempNames[0]#0x40000000 :: tempNames[1][0]=2 :: tempNames[1][1]=2
*records#0x6387010 :: *records[0]#0x40000000 :: *records[1][0]=2 :: *records[1][1]=2
nameRecords#0x6387010 :: nameRecords[1]#0x63870b0 :: nameRecords[1][0]=2 :: nameRecords[1][1]=2
nameRecords[0]#0x40000000
records#0x6387010 :: records[0]#0x40000000
Segmentation fault
All of the debug information points to the enterRecord function as being the culprit. So here it is, the evil enterRecord function...
void enterRecord(char **names, float *score)
{
names[0] = (char*)calloc(21, sizeof(char)); // allocate first name string
names[1] = (char*)calloc(21, sizeof(char)); // allocate last name string
printf("\nEnter first name: ");
fgets(names[0], 21, stdin);
if(strlen(names[0]) == 20) // IGNORE. just handles overflow from fgets.
inpurge();
remNewLine(names[0]); // removes '\n' character at end of string
printf("\nEnter last name: ");
fgets(names[1], 21, stdin);
if(strlen(names[1]) == 20) // IGNORE. just handles overflow from fgets.
inpurge();
remNewLine(names[1]); // removes '\n' character at end of string
printf("\nEnter score: ");
scanf("%f", score);
inpurge();
printf("\nCOMPLETE enterRecord\n");
return;
}
Only... no attempt at altering the affected pointer was made. The pointer value to the second element of the records array(records[1]) was passed into the function, and nothing I can see is altering the value of the pointer of the first element of the records array(records[0]), though the value of records[0] is what's causing the segfault.
I am very sorry for the length and all obfuscatory code. Again, this seems like a terrible approach to writing this program, but its what the situation calls for. I just feel bad for the poor teacher's aide who has to grade 30+ of these assignments.
Any help is welcomed.
this problem seems to be better implemented as
#define MAX_FIRST_NAME_LEN (21)
#define MAX_LAST_NAME_LEN (21)
#define MAX_SCORES (10)
// in file global memory...
static char **ppFirstNames = NULL;
static char **ppLastName = NULL;
static int **ppScores = NULL;
static int numOfEntries = 0;
// in the record input function, which needs NO parameters
scanf ( "%d", &numOfEntries );
if scanf fails, exit
ppFirstNames = malloc (numOfEntries*sizeof char*);
if malloc fails, exit
memset (ppFirstName, '\0', numOfEntries*sizeof char* );
ppLastName = malloc (numOfEntries*sizeof char*);
if malloc fails, free all, exit
memset (ppLastName, '\0', numOfEntries*sizeof char* );
ppScores = malloc (numOfEntries *sizeof int* );
if malloc fails, free all, exit
for(int i=0; i<numOfEntries; i++ )
ppFirstNames[i] = malloc( MAX_FIRST_NAME_LEN );
if malloc fails free all, exit
memset ( ppFirstNames[i], '\0', MAX_FIRST_NAME_LEN );
ppLastName[i] = malloc (MAX_LAST_NAME_LEN);
if malloc fails free all, exit
memset ( ppLastName[i], '\0', MAX_LAST_NAME_LEN );
ppScores[i] = malloc (MAX_SCORES *sizeof int);-1
if malloc fails, free all, exit
memset (ppScores[i], '\0', MAX_SCORES *sizeof int );
end for
for ( int i=0; i < numOfEntries; i++ )
now read each record
scanf( "%(MAX_FIRST_NAME_LEN-1)s", ppFirstNames[i] );
if scanf fails, free all, exit
scanf( "%(MAX_LAST_NAME_LEN-1)s", ppLastNames[i] );
if scanf fails, free all exit
for( int j=0; j< MAX_SCORES; j++ )
now read this students scores
int tempScore;
scanf( "%d", tempScore );
if scanf fails, free all, exit
if -1 == tempScore ) break;
ppScores[i][j] = tempScore;
end for
end for
The above is the pseudo code for inputting the records
and should be enough to get the input correct.
printing the info thereafter should be easy.
Example to use realloc for array multidimensional:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size_initial = 10;
int **ptr;
int i, j;
ptr = (int**) malloc(sizeof (int*) * size_initial);
for (i = 0; i < size_initial; i++) {
ptr[i] = (int*) malloc(sizeof (int) * 10);
for (j = 0; j < 10; j++)
ptr[i][j] = i+j;
}
/* realloc +10 */
ptr = (int**) realloc(ptr, sizeof (int*) * (size_initial * 2));
for (i = size_initial; i < size_initial * 2; i++) {
ptr[i] = (int*) malloc(sizeof (int) * 10);
for (j = 0; j < 10; j++) {
ptr[i][j] = i+j;
}
}
/* print values */
for (i = 0; i < 20; i++) {
for (j = 0; j < 10; j++) {
printf("ptr[%d][%d] = %d\n", i, j, ptr[i][j]);
}
}
return 0;
}

glibc detected, realloc(): invalid old size C

Admittedly what I was trying to do was at best educated guess work.
I have an array of strings, and I was trying to account for if someone entered a string that was too large, or the array received too much input (it needs to be dynamic for what I'm trying to do)
here's the section of code that's breaking:
if (strlen(token) > wordlength)
{
wordlength *= 2;
for(int j = 0; j < numwords; j++)
{
char* tmpw = realloc(wordarray[j], wordlength);
assert(tmpw != NULL);
wordarray[j] = tmpw;
printf("increased size of words to %zu \n", wordlength);
}
}
Explanations:
Token is the next word being taken in (I'm parsing a string) so I compare it to the current word length, if it's too big, i double word length and try to adjust the array accordingly.
If you need any more information let me know
initialization of wordarray:
wordarray = malloc(numwords);
for(int i = 0; i < numwords; i++)
wordarray[i] = malloc(wordlength);
Another place where realloc crashes:
if (arraycounter > numwords)
{
numwords *= 2;
char** tmp = realloc(wordarray, numwords);
assert(tmp != NULL);
wordarray = tmp;
for(int h = arraycounter; h < numwords; h++)
wordarray[h] = malloc(wordlength);
printf("increased size of wordarray to %zu \n", numwords);
}
In this situation, it would attempt to increase the size of the array if it was about to go over the initial set limit, so would not be affected due to token running out of memory (tested with 20 small words and it crashed on its attempt to resize)
You need
wordarray = malloc(numwords * sizeof *wordarray);
Also, what do you want to happen when your program is compiled without assert and run on a system with low memory? I mean, the use of assert() is probably wrong.

Resources