Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

realloc'ing array of pointers fails...

Status
Not open for further replies.

christheprogrammer

Programmer
Jul 10, 2000
258
CA
Hi All, I am trying to pass a function a char** pointer which was previously allocated via malloc(). Then I want to realloc the array of pointers inside the function but the pointers in the array get screwed..

void pass(char** arr, int* max0, int max1){
int i,j;

(*max0)++;

//Allocate new array in the last spot of arr.
arr = realloc(arr, sizeof(char*)*(*max0));
arr[(*max0)-1] = malloc(sizeof(char)*max1);

for(i=0;i<max1;i++){
// Fill in the new spot
x[(*max0)-1] = i + '0';
}
}

int main(){
char** main_arr;
int i,j,max0,max1;

max0=5;
max1=10;
arr = malloc(sizeof(char*)*max0);
for(i=0;i<max0;i++){
arr = malloc(sizeof(char)*max1);
}
for(i=0;i<max0li++){
for(j=0;j<max1;j++){
arr[j] = i + '0';
}
}
pass(arr,&max0,max1);
printf(&quot;ARR is:\n&quot;);
for(i=0;i<max0;i++){
for(j=0;j<max1;j++){
printf(&quot;%c&quot;,arrj[]);
}
printf(&quot;\n&quot;);
}
}

I get a Segmentation fault on this. I used GDB and found out that the pointers in the char** array are being clobbered upon exit of the function pass. That is, everything seems right until the function exits.
I have spent condiderable time trying to track this down. Any help would be GREATLY appreciated...
(Sorry if there are any stupid syntax errors..)
Thanks Chris
 
Chris,

This is a tricky one, but your problem lies in the fact that you are dealing with two variables with the same name &quot;arr&quot;. I believe this problem goes by the name &quot;data aliasing&quot; or something like that. (If it has a name, it is a common pitfall).

This is what is happening:

(1) In main() arr points to an allocated array of pointers each of which, in turn, points to allocated memory.
(2) You pass this pointer to pass(). Since pass() also defines a variable (parameter) named arr, you now have two pointers to the same allocated arrary of pointers. (i.e. aliased data). The two copies of the variable are as follows:
main's version which you access in main() and is
not available in pass().
pass's version which is not available to main().
(3) You now perform the realloc on the memory pointed to by arr. Because you are increasing the size of memory (and you malloced after creating the array), realloc() relocates and copies your array to a new memory location. Verify this in a debugger. arr should change.
(4) Now your two copies of arr contain different addresses. Main's version points to the original address which main() malloced and pass() freed using realloc(). In short, main's copy of arr points to garbage; the source of the segmentation fault.
(5) Now when pass() returns, its copy of arr (along with the new address) goes *poof*. You now once again have one copy of arr, but unfortunately it is the wrong version. It points to garbage.

To fix the problem you could do the following:

Pass a pointer to arr:
Code:
void pass(char*** arr, int* max0, int max1){
}
//in main:
pass(&arr,&max0,max1);
Then just add an extra * to every reference to arr in pass().

You could also contain arr in a structure such as:
Code:
typedef struct {
  char **arr ;
  int  max0 ;
  int  max1 ;
} myArray ;


void pass(myArr *arr){
}

//in main:
pass(&arr);

Of the two possibilities, I would tend toward the second implementation.

Also, there is one more potential pitfall in your program. If realloc fails, it returns a NULL pointer and leaves the existing memory untouched. Unfortunately, this null pointer blows away your existing reference and the originally allocated memory is lost.

Hope this helps.

Brudnakm
 
Hi Chris, though Brudnakm has certainly gives us a solution to the problem, I'll jus add a few more pointers all the same. hoping they will be helpful.
the problem as i see it ...
a. when arr is passed to pass, the passing by refernce holds as far as the contents of arr are changed. In this case they are available to both the functions. However in pass, it is the address of arr that is changing. Thus when control is back in main, it still refers to the old address of arr, whish is corrupted ( as this has be marked for reallocation.).
b. The prob thus can be solved with passing char ***arr , as pointed out by Brudnakm. However I am not sure how to write a realloc statement in that case !
c. another possible soluution ...
I have taken liberty to make some changes in the way of writing the code :) ... However the idea is that it helps ...
#include <stdio.h>
#define ROWMIN 5
#define ROWMAX 7
#define COL 10

/* FUNCTION PROTOTYPES */
char ** pass (char ** ) ;
void PRINT(char **, int, int) ;

int main(){
char** arr;
int i,j;

arr = (char **)malloc(sizeof(char *)*ROWMIN);
for(i=0;i<ROWMIN;i++){
arr = (char *) malloc(sizeof(char) * COL);
}

for(i=0;i<ROWMIN;i++){
for(j=0;j<COL;j++){
arr[j] = '1' + i ; //sets to row num
}
}

printf(&quot;in main...\n&quot;);
PRINT(arr,ROWMIN, COL ) ;
arr = pass(arr) ; // FUNC CALL
printf(&quot;in main after pass call...\n&quot;);
PRINT(arr, ROWMAX, COL ) ;
}

char ** pass(char** arr)
{
int i,j;

printf(&quot;IN PASS ARR is:\n&quot;);
PRINT(arr, ROWMIN, COL) ;

//Allocate new array
arr = (char **) realloc(arr,sizeof(char **) * ROWMAX);

printf(&quot;AFTER realloc ARR is:\n&quot;);
PRINT(arr, ROWMIN, COL ) ;

/***** MALLOC space for the new spots *****/
for(i=ROWMIN;i<ROWMAX;i++){
arr = (char *)malloc(sizeof(char) *COL) ;
}

for (i=ROWMIN;i<ROWMAX;i++)
for(j=0;j<10;j++)
arr[j] = '1' + i ;

return arr ;
}

void PRINT(char **arr, int row, int col)
{
int i , j ;

for (i=0;i<row;i++) {
for (j=0;j<col;j++)
printf(&quot;%c &quot;,arr[j] ) ;
printf(&quot;\n&quot;) ;
}
return ;
}

ciao :)
 
Just a couple of comments:

...However I am not sure how to write a realloc statement in that case ! ... For the record, this is how.

Code:
void *newArr ;
newArr = realloc(arr, sizeof(char*)*(*max0));
if (newArr) *arr = (char**)newArr ;

Also
Code:
char ** pass (char ** ) ;
same semantics as realloc. Nice...

Brudnakm


 
Hi,
Make the following changes in your program it will work.

The ralloc function will return a new address (which points the memory location) that should be used to access the elements after the realloc call (If realloc is not returning NULL).

The major error in your code is passing the address in the variable arr to the function pass. In the function pass the arr value will be changed, after the end to the function pass the new arr will be lost(because it is a local variable). In function main your are using the old arr value that may not exist because of the realloc. In this program I have passed the address of the vairale arr and that will solve the problem.

#include <stdio.h>
#include <malloc.h>
void pass(char ***arr, int* max0, int max1)
{
int i,j;
(*max0)++;

//Allocate new array in the last spot of arr.

*arr = (char **) realloc((void *)*arr, sizeof(char*) * (*max0));
if(*arr == NULL)
{
perror(&quot;Error : &quot;);
exit(-1);
}

//check for errors.

(*arr)[(*max0) - 1] = (char *) malloc(sizeof(char) * max1);

for(i = 0; i < max1; i++)
{
// Fill in the new spot
(*arr)[ (*max0) - 1] = i + '0';
}
}

int main()
{
char ** arr;
int i, j, max0, max1;
max0 = 5;
max1 = 10;
// use correct type castings
arr = (char **) malloc(sizeof(char*) * max0);
// check for the errors. Like if(arr == NULL) exit(0);
for(i = 0; i < max0; i++)
{
arr = (char *) malloc(sizeof(char) * max1);
//check for errors
}
for(i = 0; i < max0; i++)
{
for(j = 0; j < max1; j++)
{
arr[j] = i + '0';
}
}
pass(&arr, &max0, max1);
printf(&quot;ARR is:\n&quot;);
for(i = 0; i < max0; i++)
{
for(j = 0; j < max1; j++)
{
printf(&quot;%c&quot;, arr[j]);
}
printf(&quot;\n&quot;);
}
return 0;
}


Maniraja S
 
To reallocate inside function use triple pointer when you passing it.
Sorry missed that Manijara alredy said it already.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top