C Matrix redimensioning leading to segfault - c

I've got a array of strings (char**) and I need to do some redimensioning on it when it has reached its capacity. So, in this function I create a new array, allocate a size two time bigger than before, and for each string in the old array I allocate space for the new array and copy the content. Code is as follows:
void matrix_double (char ***arrayptr, int *size) {
char **array = *arrayptr, **newarr;
int i, wordsize;
newarr = malloc (*size * 2);
for (i = 0; i < *size; i++) {
wordsize = strlen (array[i]);
newarr[i] = malloc (wordsize + 1);
strcpy (newarr[i], array[i]);
free (array[i]);
}
*size *= 2;
free (array);
*arrayptr = newarr;
}
However, I'm getting a lot of segfaults when allocating space for the new strings in the 7th line. According to Valgrind, those malloc commands are allocating space from within the space allocated for the array, which is small - I'm using arrays of 10 or 20 strings at most - and so it overflows to other allocated areas, causing segfaults. If I bump the array memory allocation up (such as malloc (*size * 200) everything runs smoothly.
Any ideas on what's happening? Haven't seen this behavior anywhere else.

malloc argument is size in bytes. So you should call it like
malloc(sizeof(char *) * (*size) * 2);
By calling
malloc(*size * 2);
you are allocating 2*size bytes of memory which is not enough for size of pointers.

Related

realloc invalid next size for array

Hello I keep getting invalid next size when using realloc to allocate more memory to an array which im trying to add 100,000 numbers too. I dont know why because im not understanding why it wont work. My code is here below.
int main()
{
printf("starting");
int i;
int *bubbleSortArray = (int *)malloc(sizeof(int));
int numberOfElements = 0;
int randomNumber;
srand(time(NULL));
int j;
for (int j = 0; j <= 100000; j = j +1)
{
randomNumber = rand();
if(numberOfElements != 0)
{
bubbleSortArray = (int *) realloc(bubbleSortArray, numberOfElements * sizeof(int));
}
bubbleSortArray[numberOfElements] = randomNumber;
numberOfElements = numberOfElements + 1;
}
}
In the statement you need to write at least like
bubbleSortArray = (int *) realloc(bubbleSortArray, ( numberOfElements + 1 )* sizeof(int));
Otherwise this statement
bubbleSortArray[numberOfElements] = randomNumber;
invokes undefined behavior.
Also you need to use an intermediate pointer to store the return value of the call of realloc because the function can return a null pointer. In this case the previous value stored in the pointer bubbleSortArray will be lost and you will not have an access to the already allocated memory.
So it would be better to write
int *tmp = (int *) realloc(bubbleSortArray, ( numberOfElements + 1 )* sizeof(int));
if ( tmp != NULL )
{
bubbleSortArray = tmp;
}
else
{
// some other code
}
Pay attention to that these declarations
int i;
int j;
are redundant because the declared variables are not used.
Oh, this is kind of scary. I'm not sure why you're not allocating enough space up front. But this code is going to realloc 100,000 times, which is an insane thing to do. Do you know what realloc does under the hood? I'll explain.
First, it does a NEW alloc of the amount of data. So the first time you loop, numberOfElements is zero, and you use your malloc'd space. But the second time it allocates space for 2 integers, then 3 integers, then 4, et cetera.
So it allocates 8 bytes. It remembers how much it allocated last time (4 bytes -- the size of an int on most systems), and it then does a memcpy of that much space.
Then it memcpy's 8 bytes. then it memcpy's 12 bytes, and so on and so on.
Bad, bad, bad.
What most people do is keep track of two values -- the amount of space allocated (capacity) and the amount used (count or numberOfElements).
So it looks something like this:
int capacity = 16;
int *bubbleSortArray = (int *)malloc(capacity * sizeof(int));
...
if (numberOfElements >= capacity) {
// Increase capacity by whatever means you want.
// You can double it. Or you can:
capacity += 16;
bubbleSortArray = (int *) realloc(bubbleSortArray, capacity * sizeof(int));
}
Ah, and as I cut & pasted your code, I see that you used numberOfElements. So you were consistently undersizing your realloc by 1, anyway.

How to ensure a 2D array is allocated contigously in memory

I am sending a 2D array over MPI and for this to work correctly the array needs to be contiguously allocated in memory.
I am allocating it as follows:
int **array;
array = malloc(size1 * sizeof( *(array) );
for (int k = 0; k < size1; k++)
array[k] = malloc(size2 * sizeof(**(array));
Then I would like to use:
MPI_Send(array, size1*size2, MPI_INT, target_pe, tag, MPI_COMM_WORLD);
How can I ensure the array is allocated contiguously?
Currently I am trying this:
for (int k = 0; k < size1; k++)
MPI_Send(array[k], size2, MPI_INT, target_pe, tag, MPI_COMM_WORLD);
which leads to a seg fault later in an unrelated part of the program. However if I send the elements 1 by 1 it works.
How to ensure a 2D array is allocated contiguously in memory
Allocate in one step.
Example uses C99 code which supports variable length arrays. Here a pointer to a VLA is used.
// ptr is a pointer to a 2D array
int (*ptr)[size1][size2] = malloc(sizeof *ptr);
(*ptr)[0][0] = 1; // One corner of the 2D array
(*ptr)[size-1][size-1] = 2; // Opposite corner of the 2D array
I'll look into sample MPI() code later.
Use:
int (*array)[size2] = malloc(size1 * sizeof *array);
if (!array) Handle error…
If size2 is not a constant and your C implementation does not support variable length arrays, then use:
int *array = malloc(size1 * size2 * sizeof *array);
if (!array) Handle error…
In this case, you will have to use manual address arithmetic to access array elements. Instead of array[i][j], use array[i*size2 + j].
You can not ensure that by using sequential calls to malloc(). What you can do instead, you can allocate from the beginning malloc(size1 * size2) space in the memory, then you can split your allocated buffer how you desire. You can now say that array[i] is in fact array[i * size2] in the memory.
The correct way is to allocate the memory for the 2D array in on single operation. Then as arrays are not really first class citizens in C, not speaking of multi-dimensional arrays, you will have to allocate memory for an array of pointers and make its elements points to the beginning of each row:
int *mem = malloc(sizeof(*mem) * size1 * size2);
int **array = malloc(size1 * sizeof(*array));
for (int k = 0; k < size1; k++) {
array[k] = mem + k * size2 * sizeof(*mem);
}
This will ensure contiguous allocation when it matters for passing the array to routine expecting that, and still allow to access the elements as array[i][j];

Dynamic Memory Allocation for 2D Arrays in C

I'm reading about dynamic memory allocation for 2D arrays, and I'm looking at this example:
int nrows = 2;
int ncols = 5;
char **pvowels = malloc(nrows * sizeof(char));
pvowels[0] = malloc(ncols * sizeof(char));
pvowels[1] = malloc(ncols * sizeof(char));
My understanding is that the 2nd and 3rd malloc both allocate memory the size of 5 chars and pvowels[0] and pvowels[1] point to each, but I'm having trouble understanding the first malloc.
The first malloc looks like it allocates memory the size of 2 chars, and uses it to store the two pointers. But isn't a char only 256 possible values, and pointers can go up to billions? So if it's allocating memory for storing pointers, doesn't it need to be bigger than chars?
Firstly, your first malloc() is incorrect. Using nrows * sizeof(char) only allocates 2 bytes, whereas you need 2 rows of char* pointers. You have to allocate like this instead:
char **pvowels = malloc(nrows * sizeof(char*));
Or:
char **pvowels = malloc(nrows * sizeof(*pvowels));
Also note that char **pvowels is not a 2D array, but simply a pointer to a char pointer. If you were using a 2D array, such as char pvowels[][], you wouldn't need to dynamically allocate pointers on the heap. You could also just use a 2D array for your problem, such as char pvowels[2][5], as ncols and nrows seems to be fixed in this case.
Secondly, your allocations for pvowels[0] and pvowels[1] will only make space for 4 valid characters, such as "abcd", because 1 space is needed for the null terminating character \0. You should write instead:
pvowels[0] = malloc(ncols+1); /* +1 for '\0' */
pvowels[1] = malloc(ncols+1);
Note: sizeof(char) is always 1, so their is no need to include it. You should also check that malloc() returned NULL or not.
Allocating for an array of nrows pointers to char, and then separately allocating for nrows arrays of ncols chars has a disadvantage, in that the separate memory allocations are not guaranteed to be contiguous in memory. This fragmentation can lead to performance penalties.
A better approach is to allocate enough memory to hold a 2d array, and assign the resulting pointer to a pointer to an array of ncols chars. As shown here, this approach does rely on VLA's, but these have been a part of C since C99. This has the advantage of allocating memory at once, with only one allocation to free.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t nrows = 2;
size_t ncols = 5;
/* Allocate space for a 2d array */
char (*pvowels)[ncols] = malloc(sizeof (char[nrows][ncols]));
/* Another alternative */
// char (*pvowels)[ncols] = malloc(nrows * ncols);
if (pvowels == NULL) {
fprintf(stderr, "Unable to allocate memory\n");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < nrows; i++) {
for (size_t j = 0; j < ncols; j++) {
pvowels[i][j] = 'a' + i * ncols + j;
}
}
for (size_t i = 0; i < nrows; i++) {
for (size_t j = 0; j < ncols; j++) {
printf("%5c", pvowels[i][j]);
}
putchar('\n');
}
free(pvowels);
return 0;
}
Program output:
a b c d e
f g h i j
char **pvowels is a pointer to a pointer, meaning it behaves like an array declared like this:
char * pvowels[a number];
So basically, pointers to chars, and not pointers are being assigned in the example you provided.
A simple and easy to understand code:(Using just a single pointer to store and access)
#include<stdio.h>
#include<stdlib.h>
int main(){
int *a,n,r,c,i,j;
scanf("%d",&n);
r=c=n;
a=(int *)malloc(r*c*sizeof(int));
for(i=0;i<r;i++)
{
for(j=0;j<c;j++){
scanf("%d",(a+i*c+j));
}
}
for(i=0;i<r;i++)
{
for(j=0;j<c;j++){
printf("%d",*(a+i*c+j));
}
}
}
References: geeksforgeeks.org

Setup a 2D array, change size later - C

Is it possible to declare a 2D array in C, then set its size later on? I know in C you have to deal with memory and such, but I cannot find answer to this question despite all my searching.
My current example is..
int boardsize, linewin;
char array[1][1];
//boardsize is set within here.
array = [boardsize][boardsize];
With C you will need to do your own dynamic array management using pointers.
See the following articles on how to go about doing so using an allocated memory area.
Malloc a 2D array in C
Using malloc for allocation of multi-dimensional arrays with different row lengths
Since you are looking to modify these, you may also need to use the realloc() function or the free() function to release allocated memory.
For information about using the realloc() function look at the following stack overflow.
Realloc double 2D array in C
two-dimensional dynamic array (realloc in c)
EDIT - Adding an example
Here are two functions to malloc() a two dimensional array and to realloc() a two dimensional array. You could actually just use the realloc() version if you pass a NULL pointer to realloc2dCArray() for the memory area to be reallocated.
What I have tried to do is to use a single malloc() and realloc() for all of the memory needed so that you can free() the memory with a single call to free().
char **malloc2dCArray (int nRows, int nCols)
{
// use a single malloc for the char pointers to the first char of each row
// so we allocate space for the pointers and then space for the actual rows.
char **pArray = malloc (sizeof(char *) * nRows + sizeof(char) * nCols * nRows);
if (pArray) {
// calculate offset to the beginning of the actual data space
char *pOffset = (char *)(pArray + nRows);
int i;
// fix up the pointers to the individual rows
for (i = 0; i < nRows; i++) {
pArray[i] = pOffset;
pOffset += nCols;
}
}
return pArray;
}
char **realloc2dCArray (char **pOld, int nRows, int nCols)
{
// use a single realloc for the char pointers to the first char of each row
// so we reallocate space for the pointers and then space for the actual rows.
char **pArray = realloc (pOld, sizeof(char *) * nRows + sizeof(char) * nCols * nRows);
if (pArray) {
// calculate offset to the beginning of the actual data space
char *pOffset = (char *)(pArray + nRows);
int i;
// fix up the pointers to the individual rows
for (i = 0; i < nRows; i++) {
pArray[i] = pOffset;
pOffset += nCols;
}
}
return pArray;
}
To use these functions you would do something like the following:
char **pChars = malloc2dCArray (16, 8);
int i, j;
for (i = 0; i < 16; i++) {
for (j = 0; j < 8; j++) {
pChars[i][j] = 0;
}
}
To do a realloc() you will want to check that the realloc() worked so use a temporary variable and check for NULL before using it.
{
char **pChars2 = realloc2dCArray (pChars, 25, 8);
if (pChars2) pChars = pChars2;
}
You could also just use the realloc() version if you provide a NULL pointer since realloc() will do a malloc() if the pointer to the memory to realloc() is NULL.
I did some testing of this using a debugger and it looks like it is working to me.

Freeing a 2-d char array

After using this function to allocate a 2-d array:
char** make_matrix(int M, int N)
{
char** MAT = (char**)malloc(M * sizeof(char));
for (int i = 0; i < M; i++)
{
MAT[i] = (char*)malloc(N * sizeof(char));
}
return MAT;
}
I found that trying to free(M[0]) causes an assertion failure. All that I can find relating to freeing 2-d arrays use int instead of char. Yet replace every char with int above and the assertion failure disappears. Why is this, and how can I then free the entire 2-d array?
You are allocating too little memory for MAT. Change relevant line to:
char** MAT = (char**)malloc(M * sizeof(char*));
This is because MAT is array of pointers, not characters. Since your code did not allocate enough memory, it was likely writing outside of array bounds and corrupting memory.
It could work with integers because they are bigger, so with some luck you could have been allocating just enough memory (at least on 32 bit machine).
The first malloc call is M * sizeof(char) instead of sizeof(char *). The sizeof(char) would be 1 byte, the size of a char* is likely 4 bytes.
Edit: I see someone beat me to the punch. Accept the other guy's answer.
You should iterate through all the rows of the matrixes and free them first, and then finally the MAT
something like this:
void free_matrix(int M)
{
for (in i = 0; i < M; i++)
{
free(MAT[i]);
}
free(MAT);
}
To release the space (assuming it is correctly allocated), you need a call to free() corresponding to each call to malloc().
void destroy_matrix(char **MAT, int M)
{
for (int i = 0; i < M; i++)
free(MAT[i]);
free(MAT);
}
Your code works when you replace char with int because sizeof(int) == sizeof(int *) on your (32-bit) system. It's largely by coincidence; you'd be in trouble again on a 64-bit system.

Resources