Reallocate an array (pointers)

P

Piotrek

Hi,
I have no idea why my reallocation function (myadd) is breaking up my
array. I'm trying to solve it and it took me few hours already. Maybe
you can look at my code and explain me what is wrong. (I still have
problems with pointers).
I left my code as it is.
Thank you!

#include "stdafx.h" /* contains stdio.h */
#include <stdlib.h>
#include <string.h>


void *alloca(int n);
char *readr(void);
void myadd(char **A);
void myfree(void *A);

/* Main program */
int main(void){
/* Dynamically allocated array of pointers :*/
char **names;
int i,n=2;

names=(char **)alloca(n);
for(i=0;i<n;i++){
names=readr();
printf("txt: %s\n", names);
}

myadd(names);
myfree(names);
return 0;
}


/* Functions */
void myfree(void *AA){ /* Free all allocated memory */
int i;
void **A=(void **)AA;
for(i=0; A; i++) /* Finish freeing when A=NULL */
free(A);
free(AA);
}

void *alloca(int n){
void **A;
/* Avoid n==0:*/
if(n==0) n=1;
if((A=(void **)calloc(n+1, sizeof(*A)))==NULL) return NULL;
A[n]=NULL;
return A;
}

char *readr(void){
char *buf;
int i;
char c,BB[256]={'\0'};
fflush(stdin);
/* Read 255 characters max. Last char is '\0': */
for(i=0; ((c=getchar())!='\n')&&i<255; i++)
BB=c;
fflush(stdin);
/* i+1: enable myfree() to free all memory: */
if((buf=(char *)calloc(i+1,sizeof(char)))==NULL){
printf("Oops, can't allocate mem.!\n");
}
else{
strcpy(buf,BB);
return buf;
}
}


/* Should reallocate "names" and add one more entry to it :*/
void myadd(char **A){
int n;
/* Count rows of array :*/
for(n=0;A[n];n++);
/* It is supposed to reallocate "names" but it seems to break it */
if((A=(char **)realloc(A, (n+2)*sizeof(*A)))==NULL)
printf("Oops, can't reallocate mem.!\n");
A[n]=readr();
A[n+1]=NULL;
}
 
E

eric liu

I compiled and runed ur code with dev-c++,and added a slice of my test
code,but I don't think ur array is broken up.
what did u mean?
int main(void){
/* Dynamically allocated array of pointers :*/
char **names;
int i,n=2;

names=(char **)alloca(n);
if(names == NULL)
{
printf("error,names is null!\n");
exit(1);
}
for(i=0;i<n;i++){
names=readr();
printf("txt: %s\n", names);
}

myadd(names);
/*add my test code*/
i = 0;
while(names){
/*names=readr();*/
printf("txt: %s\n", names[i++]);
}
myfree(names);
return 0;
}
 
B

Barry Schwarz

Hi,
I have no idea why my reallocation function (myadd) is breaking up my
array. I'm trying to solve it and it took me few hours already. Maybe
you can look at my code and explain me what is wrong. (I still have
problems with pointers).

Your code has numerous errors and invokes undefined behavior.
I left my code as it is.
Thank you!

#include "stdafx.h" /* contains stdio.h */
#include <stdlib.h>
#include <string.h>


void *alloca(int n);
char *readr(void);
void myadd(char **A);
void myfree(void *A);

/* Main program */
int main(void){
/* Dynamically allocated array of pointers :*/
char **names;
int i,n=2;

names=(char **)alloca(n);

You need to check that alloca succeeded.
for(i=0;i<n;i++){
names=readr();


You need to check that readr succeeded.
printf("txt: %s\n", names);
}

myadd(names);
myfree(names);
return 0;
}


/* Functions */
void myfree(void *AA){ /* Free all allocated memory */
int i;
void **A=(void **)AA;
for(i=0; A; i++) /* Finish freeing when A=NULL */
free(A);
free(AA);
}

void *alloca(int n){
void **A;
/* Avoid n==0:*/
if(n==0) n=1;
if((A=(void **)calloc(n+1, sizeof(*A)))==NULL) return NULL;


This is a problem waiting to happen. You are allocating space for n+1
objects of type void*. In this instance, you will use the space to
store values of type char*. The standard guarantees that void* and
char* have the same size (and representation). However, if you ever
use this function to allocate space for different types of pointers,
you have no idea if you will allocate enough space. It is entirely
possible for sizeof (int*) to be greater than sizeof (void*).

Why are you using calloc? Do you think initializing a pointer to all
bits 0 has some benefit?
A[n]=NULL;
return A;
}

char *readr(void){
char *buf;
int i;
char c,BB[256]={'\0'};
fflush(stdin);

This invokes undefined behavior. fflush is defined only for output
streams.
/* Read 255 characters max. Last char is '\0': */
for(i=0; ((c=getchar())!='\n')&&i<255; i++)

getchar returns an int. c is a char. It is possible for getchar to
return a value that will not fit in a char. If so, this would invoke
undesirable (either undefined or implementation defined) behavior.
BB=c;
fflush(stdin);
/* i+1: enable myfree() to free all memory: */
if((buf=(char *)calloc(i+1,sizeof(char)))==NULL){
printf("Oops, can't allocate mem.!\n");
}
else{
strcpy(buf,BB);
return buf;
}


If calloc failed, you do not return anything. This will invoke
undefined behavior. Did you compiler not complain about reaching the
end of the function without returning a value?
}


/* Should reallocate "names" and add one more entry to it :*/
void myadd(char **A){
int n;

This is an automatic variable that is not initialized. Therefore its
value is indeterminate.
/* Count rows of array :*/
for(n=0;A[n];n++);

Any attempt to evaluate the indeterminate value in n invokes undefined
behavior.
/* It is supposed to reallocate "names" but it seems to break it */
if((A=(char **)realloc(A, (n+2)*sizeof(*A)))==NULL)

n contains garbage. It could be negative. n+2 has no meaning.
printf("Oops, can't reallocate mem.!\n");
A[n]=readr();

When realloc fails, you print the error message but then procede to
use A as if it contained a valid pointer. This also invokes undefined
behavior.
A[n+1]=NULL;

Since C passes by value, when you return from this function, the value
of A is discarded. The value of names in the calling function is
unchanged. If the realloc succeeded and allocated a new block of
memory (instead or reusing the existing block), that value will no
longer point to the allocated area. In fact, that value becomes
indeterminate and any use of it in the calling function invokes
undefined behavior.


Remove del for email
 
P

pete

CBFalconer said:
Piotrek wrote:

Better to precede main with these, thus dispensing with the
prototypes. This technique reduces the possibility of silly
errors.

Which silly errors are you refering to?
 
P

pete

Barry said:
/* Count rows of array :*/
for(n=0;A[n];n++);

Any attempt to evaluate the indeterminate value in n invokes undefined
behavior.

He assigned a value of zero to n, in the above shown code.
Since C passes by value, when you return from this function, the value
of A is discarded. The value of names in the calling function is
unchanged. If the realloc succeeded and allocated a new block of
memory (instead or reusing the existing block), that value will no
longer point to the allocated area. In fact, that value becomes
indeterminate and any use of it in the calling function invokes
undefined behavior.

That's the ticket!

void myadd(char ***A)
{
size_t n;
void *p;

for (n = 0; (*A)[n] != NULL; ++n) {
;
}
p = realloc(*A, (n + 2) * sizeof(**A));
if (p != NULL) {
*A = p;
(*A)[n + 1] = NULL;
(*A)[n] = readr();
} else {
puts("p == NULL");
exit(EXIT_FAILURE);
}
}
 
P

pete

Piotrek said:
Hi,
I have no idea why my reallocation function (myadd) is breaking up my
array. I'm trying to solve it and it took me few hours already. Maybe
you can look at my code and explain me what is wrong. (I still have
problems with pointers).
I left my code as it is.
Thank you!

I agree with everything that Barry Schwarz
said in his reply to your post,
except the part about indeterminate n;
I think he just didn't see the assignment to n.


/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STRINGS 2

char **alloca(size_t n);
char *readr(void);
void myadd(char ***A);
void myfree(char **A);

int main(void)
{
char **names;
size_t i, n = STRINGS;

names = alloca(n);
if (names == NULL) {
puts("names == NULL");
exit(EXIT_FAILURE);
}
for (i = 0; i != n; ++i) {
names = readr();
printf("txt: %s\n", names);
}
myadd(&names);
puts("\n");
for (i = 0; names != NULL; ++i) {
printf("txt: %s\n", names);
}
myfree(names);
puts("\nfreed");
return 0;
}

void myfree(char **A)
{
size_t i;

for (i = 0; A != NULL; ++i) {
free(A);
}
free(A);
}

char **alloca(size_t n)
{
char **A;

if ((A = malloc((n + 1) * sizeof *A)) != NULL) {
A[n] = NULL;
}
return A;
}

char *readr(void)
{
char *buf;
size_t i;
int c;
char BB[256] = {'\0'};

for (i = 0; ((c = getchar()) != '\n') && i != 255; ++i) {
if (c == EOF) {
puts("c == EOF");
exit(EXIT_FAILURE);
}
BB = (char)c;
}
if ((buf = malloc(i + 1)) != NULL) {
strcpy(buf, BB);
} else {
puts("buf == NULL");
exit(EXIT_FAILURE);
}
return buf;
}

void myadd(char ***A)
{
size_t n;
void *p;

for (n = 0; (*A)[n] != NULL; ++n) {
;
}
p = realloc(*A, (n + 2) * sizeof(**A));
if (p != NULL) {
*A = p;
(*A)[n + 1] = NULL;
(*A)[n] = readr();
} else {
puts("p == NULL");
exit(EXIT_FAILURE);
}
}

/* END new.c */
 
B

B. Augestad

Piotrek said:
Hi,
I have no idea why my reallocation function (myadd) is breaking up my
array. I'm trying to solve it and it took me few hours already. Maybe
you can look at my code and explain me what is wrong. (I still have
problems with pointers).
I left my code as it is.
Thank you!

#include "stdafx.h" /* contains stdio.h */
#include <stdlib.h>
#include <string.h>


void *alloca(int n);

Just to add one minor point to the discussion. alloca() is a common
extension on many systems. It is also a built in function in gcc, so
unless you compile your program with -ansi or -std=c[89]9, your program
will fail in mysterious ways.

It's probably a good idea to rename alloca() to something else.

HTH
Bjørn

[snip]
 
B

Barry Schwarz

Barry said:
/* Count rows of array :*/
for(n=0;A[n];n++);

Any attempt to evaluate the indeterminate value in n invokes undefined
behavior.

He assigned a value of zero to n, in the above shown code.

Yes, I missed that. I guess horizontal white space is becoming more
than a luxury.


Remove del for email
 
D

David Thompson

ur is not a legal language on c.l.c, it is an ancient Abysinian
city. U hasn't posted here for some time. This is not a
chat-room.
Ur was in Mesopotamia (now Iraq) not Abyssinia (now ~Ethiopia).
Otherwise concur.

Plus, runes are a source form. If you are going to rune a program,
which we don't recommend as it (a) isn't defined by the C standard and
(b) doesn't work well in Usenet postings, do it _before_ compiling.

:-!
- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,499
Latest member
DewittK739

Latest Threads

Top