PDA

View Full Version : [C] problema allocazione puntatore a puntatore


marilynm69
04-04-2018, 13:45
Ciao a tutti, ho un problema con una funzione che deve prendere in ingresso un numero variable di stringhe e creare un puntatore ad array di puntatore a char (le stringhe caricate).
codice:

void addit( char *title, char *elems,...)

{
va_list argP;
va_start(argP, elems);

char **mitems;
mitems=(char **)xMalloc(sizeof(char*));

char *p;
int i;
for (i=0; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=xRealloc(mitems,sizeof(mitems)+sizeof(*mitems));
mitems[i]=(char *)xCalloc(1, sizeof(char*));
mitems[i]=p;

printf("\n\t%d: %s",i+1, p);
printf("\n\t\t+++ %s",mitems[i]);


}
printf("\n\n%d arguments\n", i);
va_end(argP);
}


int main()
{

addit("FILE","new","open","save","backup","print","setup","exit",NULL);

return 0;
}



valgrind:

==13035== Memcheck, a memory error detector
==13035== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==13035== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==13035== Command: ./serate\ project
==13035==

1: open
+++ open
2: save
==13035== Invalid write of size 8
==13035== at 0x4077CD: addit (Menu.c:440)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035== Address 0x6dbd620 is 0 bytes after a block of size 16 alloc'd
==13035== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13035== by 0x406B60: xRealloc (Menu.c:32)
==13035== by 0x40779B: addit (Menu.c:439)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035==
==13035== Invalid write of size 8
==13035== at 0x4077F1: addit (Menu.c:441)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035== Address 0x6dbd620 is 0 bytes after a block of size 16 alloc'd
==13035== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13035== by 0x406B60: xRealloc (Menu.c:32)
==13035== by 0x40779B: addit (Menu.c:439)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035==
+++ save
==13035== Invalid read of size 8
==13035== at 0x407832: addit (Menu.c:444)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035== Address 0x6dbd620 is 0 bytes after a block of size 16 alloc'd
==13035== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13035== by 0x406B60: xRealloc (Menu.c:32)
==13035== by 0x40779B: addit (Menu.c:439)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035==
3: backup
+++ backup
4: print
+++ print
5: setup
+++ setup
6: exit
+++ exit

6 arguments
==13035==
==13035== HEAP SUMMARY:
==13035== in use at exit: 64 bytes in 7 blocks
==13035== total heap usage: 14 allocs, 7 frees, 1,176 bytes allocated
==13035==
==13035== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==13035== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13035== by 0x406B60: xRealloc (Menu.c:32)
==13035== by 0x40779B: addit (Menu.c:439)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035==
==13035== 48 bytes in 6 blocks are definitely lost in loss record 2 of 2
==13035== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13035== by 0x406B14: xCalloc (Menu.c:22)
==13035== by 0x4077CC: addit (Menu.c:440)
==13035== by 0x40791C: temp (Menu.c:456)
==13035== by 0x406A93: main (main.c:32)
==13035==
==13035== LEAK SUMMARY:
==13035== definitely lost: 64 bytes in 7 blocks
==13035== indirectly lost: 0 bytes in 0 blocks
==13035== possibly lost: 0 bytes in 0 blocks
==13035== still reachable: 0 bytes in 0 blocks
==13035== suppressed: 0 bytes in 0 blocks
==13035==
==13035== For counts of detected and suppressed errors, rerun with: -v
==13035== ERROR SUMMARY: 14 errors from 5 contexts (suppressed: 0 from 0)


a me servirebbe una cosa così:

https://s14.postimg.org/qlhg7w8tt/x_forum.jpg

il problema più grosso è ovviamente quello della memoria, poi non capisco perchè inizia a prendermi il secondo dei parametri variabili("open"), invece che dal prino ("new").
grazie anticipatamente...

P.S. le funzioni xMalloc, xCalloc, xRealloc sono remplicemente malloc, calloc e realloc con il controllo sulla memoria allocata, e restituiscono il puntatore o chiudono il programma

grigor91
04-04-2018, 17:17
Ciao a tutti, ho un problema con una funzione che deve prendere in ingresso un numero variable di stringhe e creare un puntatore ad array di puntatore a char (le stringhe caricate).
codice:

void addit( char *title, char *elems,...)

{
va_list argP;
va_start(argP, elems);

...

}


int main()
{

addit("FILE","new","open","save","backup","print","setup","exit",NULL);

return 0;
}




il problema più grosso è ovviamente quello della memoria, poi non capisco perchè inizia a prendermi il secondo dei parametri variabili("open"), invece che dal prino ("new").
grazie anticipatamente...

P.S. le funzioni xMalloc, xCalloc, xRealloc sono remplicemente malloc, calloc e realloc con il controllo sulla memoria allocata, e restituiscono il puntatore o chiudono il programma


title punta al primo carattere di "FILE", elems al primo carattere di "new", quindi il primo argomento variabile è "open".

Inoltre quando effettui la reallocazione la nuova dimensione è formata dalla somma della dimensione dei due puntatori, che quindi sarà sempre costante (8 o 16 byte in base all'architettura).

misterx
04-04-2018, 18:12
se non ho capito male

main (int argc, char *argv[] )
{

}

e fa già quello che chiedi

marilynm69
04-04-2018, 18:21
in va_start(argP, elems);
elemsnon deve essere l'ultimo degli argomenti fissi? quindi new,...

char * title è un'altra cosa a parte da quella lista...inizia da open anche se sostituisco char *title con int title e ci passo un numero, come potrebbe pure tranquillamente essere...

per riallocare non ho capito come allora dovrei fare...

marilynm69
04-04-2018, 18:23
se non ho capito male

main (int argc, char *argv[] )
{

}

e fa già quello che chiedi

non mi serve,nell'esempio c'è main ma la funzione è interna ad un altra, a sua volta interna al main...

marilynm69
04-04-2018, 19:17
per l'allocazione ho risolto, grazie grigor91 per avermi fatto notare...
ho fatto così:

…..
char **mitems;
mitems=(char **)xMalloc(sizeof(char*));
int i;
for (i=0; ((p=va_arg(argP,char*)) !=NULL) ; i++ )

{
mitems=(char **)xRealloc(mitems,(i+1)*sizeof(char*));
mitems[i]=p;

printf("\n\t%d: %s",i+1, p);
printf("\n\t\t+++ %s",mitems[i]);
}
…..


per gli argomenti variabili nessun suggerimento?

misterx
04-04-2018, 20:10
io non ho capito se devi prendere n argomenti in numero e lunghezza variabile e memorizzarli in un array: è così?

marilynm69
04-04-2018, 21:08
io non ho capito se devi prendere n argomenti in numero e lunghezza variabile e memorizzarli in un array: è così?

esatto....per l'array e l'allocazione risolto, non capisco perchè mi inizia a prendere gli argomenti dal secondo

se faccio void addit(char *elems,...)
funziona come dovrebbe, ma a me serve passare argomenti prima, e per chiarezza un altro char * come titolo...

misterx
05-04-2018, 09:41
int main()
{
addit("FILE","new", "open", "save", "backup", "print", "setup", "exit", NULL);

return 0;
}
//---------------------------------------------------------------------------

void addit( char *title, char *elems ...)

{
va_list argP;
va_start(argP, elems);

char **mitems;
mitems=(char **)malloc(sizeof(char*));

char *p;
int i;

for (i=0; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,sizeof(mitems)+sizeof(*mitems));
mitems[i]=(char *)calloc(1, sizeof(char*));
mitems[i]=p;

printf("\n\t%d: %s",i+1, p);
printf("\n\t\t+++ %s",mitems[i]);
}

printf("\n\n%d arguments\n", i);
va_end(argP);

getchar();
}
//---------------------------------------------------------------------------



1: open
+++ open
2: save
+++ save
3: backup
+++ backup
4: print
+++ print
5: setup
+++ setup
6: exit
+++ exit

6 arguments




int main()
{
addit("FILE","new", "open", "save", "backup", "print", "setup", "exit", NULL);

return 0;
}
//---------------------------------------------------------------------------

void addit( char *title ...)

{
va_list argP;
va_start(argP, title);

char **mitems;
mitems=(char **)malloc(sizeof(char*));

char *p;
int i;

for (i=0; ((p=va_arg(argP, char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,sizeof(mitems)+sizeof(*mitems));
mitems[i]=(char *)calloc(1, sizeof(char*));
mitems[i]=p;

printf("\n\t%d: %s",i+1, p);
printf("\n\t\t+++ %s",mitems[i]);
}

printf("\n\n%d arguments\n", i);
va_end(argP);

getchar();
}
//---------------------------------------------------------------------------



1: new
+++ new
2: open
+++ open
3: save
+++ save
4: backup
+++ backup
5: print
+++ print
6: setup
+++ setup
7: exit
+++ exit

7 arguments

marilynm69
05-04-2018, 11:13
fosse solo un elenco che mi serve andrebbe bene, ma a me serve passare un puntatore a una struttura, il titolo a parte, e gli elementi un altra cosa...
ad esempio la funzione execl:

int execl (const char *__path, const char *__arg, ...)

come vedi sono 2 cose differenti path e arguments....a me serve title e gli elementi...in ogni caso, anche come hai fatto tu, dov'è finito "FILE"? un probabile utente si vedrà sparire la prima variabile, perchè mai?

anche semplificando tutto:

void addit(char * elems,...){

va_list argP;
va_start(argP, elems);
char *p;
int i;
for (i=0; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
printf("\n%s",p);
}
va_end(argP);
}

stampa da new:
new
open
save
backup
print
setup
exit


tolgo pure il ciclo for:

void addit(char * elems,...){

va_list argP;
va_start(argP, elems);
printf("\n%s",va_arg(argP,char*));
va_end(argP);
}


stampa " new " perchè? dove va a finire la prima variabile?

marilynm69
05-04-2018, 12:21
void addit(char * elems, ...){

va_list argP;
va_start(argP, elems);

printf("\n%s",elems);
printf("\n%s",va_arg(argP,char*));

va_end(argP);
}

la risolvo così, prendo elems come primo elemento, ci faccio il controllo se esiste almeno quello e continuo con il ciclo ,con va_start(argP, elems);

Grazie misterx per avermi portato comunque a risolverlo ;)

PS. devo mettere risolto nel titolo? se si come lo modifico?

misterx
06-04-2018, 20:37
però se si fa a questo modo, funziona come vuoi tu, invertendo i parametri della funzione

da così void addit(char *title, char *elems ...); a così void addit(char *elems, char *title ...);


void addit(char *elems, char *title ...);

int main()
{
addit("FILE","new", "open", "save", "backup", "print", "setup", "exit", NULL);

return 0;
}
//---------------------------------------------------------------------------

void addit(char *elems, char *title ...)

{
va_list argP;
va_start(argP, elems);

char **mitems;
mitems=(char **)malloc(sizeof(char*));

char *p;
int i;

for (i=0; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,sizeof(mitems)+sizeof(*mitems));
mitems[i]=(char *)calloc(1, sizeof(char*));
mitems[i]=p;

printf("\n\t%d: %s",i+1, p);
printf("\n\t\t+++ %s",mitems[i]);
}

printf("\n\n%d arguments\n", i);
va_end(argP);

getchar();
}
//---------------------------------------------------------------------------




sembra più un problema di posizione dei parametri

marilynm69
09-04-2018, 12:32
stessa cosa, comunque l'ho risolto così...ora il problema è un altro, ma il puntatore è puntatore a puntatore a struttura, e viene passato alla funzione addit per poi riallocare di volta in volta...non so se postarlo sempre quà, anche perchè il titolo sarebbe simile


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


typedef struct s_drop_down_menu_labels
{
char *title;
char **items;
} MenuLabels;

MenuLabels ** ml_init(void)
{
MenuLabels **ml;
ml=(MenuLabels **)calloc(2,sizeof(MenuLabels*));
ml[1]=NULL;
return ml;
}



void addit(MenuLabels **mlabels, char *title, char *elems,...)
{

int j;
for (j=0; mlabels[j]!=NULL ; j++ );
printf("\n\nCHECK:MenuLabels has %d menu",j);

mlabels=(MenuLabels **)realloc(mlabels,(j+2)*sizeof(MenuLabels*));

mlabels[j]=(MenuLabels *)malloc(1*sizeof(MenuLabels));

mlabels[j+1]=NULL;




mlabels[j]->title=title;

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int i=0;
char **mitems=NULL;
mitems=(char **)malloc(sizeof(char*));
mitems[i]=elems;

va_list argP;
va_start(argP, elems);

char *p;
for (i=1; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=p;
}

if (!p)
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=NULL;
}

va_end(argP);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

mlabels[j]->items=mitems;
}



int main()
{
MenuLabels **ml;
ml=ml_init();
addit(ml,"FILE","new","open","save","backup","print","setup","exit",NULL);
addit(ml,"AFILE","Anew","Asave","Abackup","Aexit",NULL);
addit(ml,"BFILE","Bnew","Bopen","Bsave","Bprint","Bexit",NULL);
addit(ml,"CFILE","Cnew","Copen","Csave","Cbackup","Cprint","Csetup","Cexit",NULL);
addit(ml,"DFILE","Dnew","Dsave","Dbackup","Dexit",NULL);
addit(ml,"EFILE","Enew","Eopen","Esave","Eprint","Eexit",NULL);

free(ml);

fprintf(stdout,"\n\033[1;91m***END***\033[0m\n");
return 0;
}


output terminale:


CHECK:MenuLabels has 0 menu

CHECK:MenuLabels has 1 menu

CHECK:MenuLabels has 2 menu

CHECK:MenuLabels has 2 menu

CHECK:MenuLabels has 2 menu

CHECK:MenuLabels has 2 menu
***END***


output Valgrind:

==13907== Memcheck, a memory error detector
==13907== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==13907== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==13907== Command: ./prove
==13907==


==13907== Invalid read of size 8
==13907== at 0x400812: addit (main.c:26)
==13907== by 0x400B27: main (main.c:75)
==13907== Address 0x5204040 is 0 bytes inside a block of size 16 free'd
==13907== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x400855: addit (main.c:29)
==13907== by 0x400AF1: main (main.c:74)
==13907== Block was alloc'd at
==13907== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x40075C: ml_init (main.c:15)
==13907== by 0x400AB0: main (main.c:73)
==13907==
CHECK:MenuLabels has 0 menu

==13907== Invalid free() / delete / delete[] / realloc()
==13907== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x400855: addit (main.c:29)
==13907== by 0x400B27: main (main.c:75)
==13907== Address 0x5204040 is 0 bytes inside a block of size 16 free'd
==13907== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x400855: addit (main.c:29)
==13907== by 0x400AF1: main (main.c:74)
==13907== Block was alloc'd at
==13907== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x40075C: ml_init (main.c:15)
==13907== by 0x400AB0: main (main.c:73)
==13907==
==13907== Invalid write of size 8
==13907== at 0x400882: addit (main.c:31)
==13907== by 0x400B27: main (main.c:75)
==13907== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==13907==
==13907==
==13907== Process terminating with default action of signal 11 (SIGSEGV)
==13907== Access not within mapped region at address 0x0
==13907== at 0x400882: addit (main.c:31)
==13907== by 0x400B27: main (main.c:75)
==13907== If you believe this happened as a result of a stack
==13907== overflow in your program's main thread (unlikely but
==13907== possible), you can try to increase the size of the
==13907== main thread stack using the --main-stacksize= flag.
==13907== The main thread stack size used in this run was 8388608.
CHECK:MenuLabels has 0 menu==13907==
==13907== HEAP SUMMARY:
==13907== in use at exit: 112 bytes in 4 blocks
==13907== total heap usage: 14 allocs, 10 frees, 1,392 bytes allocated
==13907==
==13907== 16 bytes in 1 blocks are definitely lost in loss record 2 of 4
==13907== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x400881: addit (main.c:31)
==13907== by 0x400B27: main (main.c:75)
==13907==
==13907== 96 (16 direct, 80 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==13907== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13907== by 0x400855: addit (main.c:29)
==13907== by 0x400AF1: main (main.c:74)
==13907==
==13907== LEAK SUMMARY:
==13907== definitely lost: 32 bytes in 2 blocks
==13907== indirectly lost: 80 bytes in 2 blocks
==13907== possibly lost: 0 bytes in 0 blocks
==13907== still reachable: 0 bytes in 0 blocks
==13907== suppressed: 0 bytes in 0 blocks
==13907==
==13907== For counts of detected and suppressed errors, rerun with: -v
==13907== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)



sembra ci sia un errore in mlabels=(MenuLabels **)realloc(mlabels,(j+2)*sizeof(MenuLabels*));

sono giorni che non ne esco...la parte tra i due commenti "/*+++...+++*/" è a posto

marilynm69
09-04-2018, 15:10
Risolto finalmente:yeah: ....ecco il codice:

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


typedef struct s_drop_down_menu_labels
{
char *title;
char **items;
} MenuLabels;

MenuLabels ** ml_init(void)
{
MenuLabels **ml;
ml=(MenuLabels **)calloc(2,sizeof(MenuLabels*));
ml[1]=NULL;
return ml;
}



void addit(MenuLabels ***mlabels, char *title, char *elems,...)
{

int j;
for (j=0; (*mlabels)[j]!=NULL ; j++ );
printf("\n\nCHECK:MenuLabels has %d menu",j);

*mlabels=(MenuLabels **)realloc(*mlabels,(j+2)*sizeof(MenuLabels*));

(*mlabels)[j]=(MenuLabels *)malloc(1*sizeof(MenuLabels));

(*mlabels)[j+1]=NULL;




(*mlabels)[j]->title=title;

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int i=0;
char **mitems=NULL;
mitems=(char **)malloc(sizeof(char*));
mitems[i]=elems;

va_list argP;
va_start(argP, elems);

char *p;
for (i=1; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=p;
}

if (!p)
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=NULL;
}

va_end(argP);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

(*mlabels)[j]->items=mitems;
free(mitems);
}


int main()
{
MenuLabels **ml;
ml=ml_init();
addit(&ml,"FILE","new","open","save","backup","print","setup","exit",NULL);
addit(&ml,"AFILE","Anew","Asave","Abackup","Aexit",NULL);
addit(&ml,"BFILE","Bnew","Bopen","Bsave","Bprint","Bexit",NULL);
addit(&ml,"CFILE","Cnew","Copen","Csave","Cbackup","Cprint","Csetup","Cexit",NULL);
addit(&ml,"DFILE","Dnew","Dsave","Dbackup","Dexit",NULL);
addit(&ml,"EFILE","Enew","Eopen","Esave","Eprint","Eexit",NULL);


printf("\n**********CHECK: %s",ml[0]->title);

for (int i=0;ml[i]!=NULL ;i++ )
free(ml[i]);

fprintf(stdout,"\n\033[1;91m***END***\033[0m\n");
return 0;
}


unica cosa rimangono byte da deallocare che non capisco quali siano:

==18805== Memcheck, a memory error detector
==18805== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18805== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==18805== Command: ./prove
==18805==


CHECK:MenuLabels has 0 menu

CHECK:MenuLabels has 1 menu

CHECK:MenuLabels has 2 menu

CHECK:MenuLabels has 3 menu

CHECK:MenuLabels has 4 menu

CHECK:MenuLabels has 5 menu
**********CHECK: FILE
***END***
==18805==
==18805== HEAP SUMMARY:
==18805== in use at exit: 56 bytes in 1 blocks
==18805== total heap usage: 52 allocs, 51 frees, 2,504 bytes allocated
==18805==
==18805== 56 bytes in 1 blocks are definitely lost in loss record 1 of 1
==18805== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18805== by 0x400858: addit (main.c:29)
==18805== by 0x400C33: main (main.c:79)
==18805==
==18805== LEAK SUMMARY:
==18805== definitely lost: 56 bytes in 1 blocks
==18805== indirectly lost: 0 bytes in 0 blocks
==18805== possibly lost: 0 bytes in 0 blocks
==18805== still reachable: 0 bytes in 0 blocks
==18805== suppressed: 0 bytes in 0 blocks
==18805==
==18805== For counts of detected and suppressed errors, rerun with: -v
==18805== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)