DOMANDA di nuovo tabelle in C: la dimensione dell'array dinamico, come.

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
C:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
    int size,i,l;

    int rows = 2;
    int cols = 5;

    int numcols;

    int newrows;
    int newcols;

    char ***table;


    //allocate matrix [ROWS][COLUMS][CHARS]
    table = malloc(rows * sizeof(char **));

    //allocate row matrix that has cols 5
    for(i = 0; i < rows; i++)
        table[i] = malloc(cols * sizeof(char *));

    //allocate cell matrix
    for(i = 0; i < rows; i++)
        for(l = 0; l < cols; l++){
            table[i][l] = malloc(sizeof(char));
            table[i][l] = NULL;
        }


    newrows = 2;
    newcols = 2;

    table[0][0] = "00";
    table[0][1] = "01";
    table[0][2] = "02";
    table[0][3] = "03";
    table[0][4] = "04";

    table[1][0] = "10";
    table[1][1] = "11";
    table[1][2] = "12";
    table[1][3] = "13";
    table[1][4] = "14";

    //modify size add the rows
    table = realloc(table,(rows + newrows) * sizeof(char**));

    //add memory new rows
    for(i = rows; i < (rows + newrows); i++)
        table[i] = malloc(cols * sizeof(char *));

    //add other columns to all rows
    for(i = 0; i < (rows + newrows); i++)
        table[i] = realloc(table[i],(cols + newcols) * sizeof(char *));

   //add memory new cell
    for(i = rows; i < rows + newrows; i++)
        for(l = cols; l < cols + newcols; l++)
        {
            table[i][l] = malloc(sizeof(char));
            table[i][l] = NULL;
        }



    table[2][0] = "20";
    table[2][5] = "25";
    table[2][6] = "26";
    table[3][5] = "35";
    table[3][6] = "36";

    for(i = 0; i < rows + newrows; i++)
        for(l = 0; l < cols + newcols; l++)
        {
            if( (cols + newcols) - 1  == l)
                printf("%s\t\n",table[i][l]);
            else
                printf("%s\t",table[i][l]);
        }


    for(i = 0; i < (rows + newrows); i++)
    {
        //HERE THE SIZE OF table[i] and table[i][l]
        numcols = 0;

        //from table field
    }


    return 0;

}
 

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
Sembra che non si possa conoscere la dimensione di un array ottenuto con i puntatori. Diverso se array fosse statico allora

char array[4];
Int dim = sizeof(array)/sizeof(array[0])

funzionerebbe.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Di solito tieni traccia tu del numero di elementi che allocchi.
Infatti non è un caso che anche alle funzioni normalmente si passi il puntatore più il nr. di elementi.
 

Andretti60

Utente Èlite
6,440
5,091
Il tuo codice è zeppo di errori, scusa ma sono a letto bevendo la mia prima tazza di caffè giornaliero, sto usando il iPad, non sono in condizione di farteli notare tutti. Non ti scoraggiare, questa è una parte tosta del linguaggio.

Come dice il nostro amico @DispatchCode, le librerie C non tengono conto di quanta memoria è allocata, non solo, ma se leggi la documentazione noterai che assicurano di allocare “almeno” quanta memoria richiesta, ma in genere la allocano in multipli del minimo blocco di memoria (quanto sia non è specificato, dipende dalla libreria, ma è almeno 1K). Per questo motivo non è raccomandato allocare dinamicamente piccole quantità di memoria, si finisce con il allocare molta di più.

Il motivo per cui il linguaggio C non offre una allocazione di memoria più semplice (e conseguente disallocazione) è per motivi di efficienza, lo stesso motivo per cui non fa nessun controllo che si stia accedendo a una locazione legale, o che l’indice di un vettore sia nei limiti concessi. Il linguaggio C non venne creato per essere un linguaggio multi uso, bensì per scrivere un sistema operativo (Unix), è quindi un linguaggio minimale le cui funzionalità sono molto simili al linguaggio macchina, solo con una sintassi più facile e immediata. Non per nulla ai giorni nostri (ossia adesso) viene usato quasi esclusivamente per didattica, per funzioni interne del sistema operativo, per device driver, per sistemi embedded, ossia in quelle circostanze dove è essenziale l’efficienza e la compattezza dell’’eseguibile, senza troppa richiesta di librerie supplementari.

I linguaggi moderni hanno quasi tutti abbandonato l’uso dei puntatori, anche chi programma in C non li usa direttamente ma fa uso di una struttura dati che implementa i “Smart Pointer”, una struttura (tipicamente una “struct”) che assieme al puntatore stesso unisce altri dati relativi alla memoria associata. Non scendo nei dettagli perché il discorso è complesso (richiede un intero corso universitario). Studiare i puntatori del linguaggio C è indispensabile per potere poi capire come funzionano i Smart Pointer e la moderna gestione della memoria, come per esempio tecniche come il “garbage collector”, ma in pratica la allocazione dinamica in C si cerca di limitarla all’essenziale. Per esempio in un sistema embedded si evita come la peste :) si lavora con un piccolo sistema con memoria limitata e non si spreca tempo di allocarla e liberarla ogni volta (anche in questo caso non scendo nei dettagli).
 
  • Mi piace
Reazioni: DispatchCode

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
Il tuo codice è zeppo di errori, scusa ma sono a letto bevendo la mia prima tazza di caffè giornaliero, sto usando il iPad, non sono in condizione di farteli notare tutti. Non ti scoraggiare, questa è una parte tosta del linguaggio.
In che senso zeppo di errori? Compila e ti mostra una tabella dinamica del tipo char*. Se vuole puo dirmi dove ne incontra cosi posso capire.
linguaggi moderni hanno quasi tutti abbandonato l’uso dei puntatori, anche chi programma in C non li usa direttamente ma fa uso di una struttura dati che implementa i “Smart Pointer”, una struttura (tipicamente una “struct”) che assieme al puntatore stesso unisce altri dati relativi alla memoria associata.
Sono d'accordo.
Per esempio in un sistema embedded si evita come la peste :) si lavora con un piccolo sistema con memoria limitata e non si spreca tempo di allocarla e liberarla ogni volta (anche in questo caso non scendo nei dettagli).
Ok capito, ma il mio intento è creare questa tabella che sia dinamica in dimensioni e in tipi. Ci riuscirò prima o poi.
Post unito automaticamente:

Non ti scoraggiare, questa è una parte tosta del linguaggio.

Insomma ho come obiettivo a lungo termine di imparare i sistemi embedded. Un po mi scoraggia ma so che ci vogliono i tentativi.
 
Ultima modifica:

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
for(i = rows; i < rows + newrows; i++) for(l = cols; l < cols + newcols; l++) { table[l] = malloc(sizeof(char)); table[l] = NULL; }
Anche io da smartphone, quindi non priorio comodissimo.

Comunque una cosa già errata è il fatto che allocchi ogni singolo elemento per porlo a null. Per altro sono tutti memory leak.
Inoltre non si alloca mai così poca memoria per motivi di efficienza (poi così allocchi 1 solo carattere, non penso sia ciò che vuoi... inoltre non ti serve allocare, appunto).

Come dice Andretti malloc e compagnia allocano a una certa granularità.

Tutte le stringhe "harcodate" puoi metterle in un array e accedervi tramite un indice, così ti basta un ciclo per inizializzare la matrice.
 

Andretti60

Utente Èlite
6,440
5,091
Il fatto che un codice “compila” (specie in linguaggio C) non significa non abbia errori :) la vita sarebbe molto più facile.
Il tuo codice funziona perché inizializzi le celle con puntatori di variabile statiche, per cui non serve allocare i puntatori (come ti ha fatto notare @DispatchCode hai creato una miriade di memory leak)

secondo me sarebbe meglio che prima di imparare la allocazione di memoria dinamica e come cambiarla, imparassi a usare i puntatori. Stai facendo troppa confusione e non li stai usando correttamente.
 

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
Non sono d'accordo.Ma accetto qualunque critica. Queste instruzioni le avevo messe per capire cosa succede con "una malloc sopra un'altra malloc". Se a differenza della calloc non venivano inizializzate.
for(i = rows; i < rows + newrows; i++) for(l = cols; l < cols + newcols; l++) { table[l] = malloc(sizeof(char)); table[l] = NULL; }
Indubbiamente è superflua. Mi informerò meglio sui memory leak non mi convincono. Ma saresti cosi gentile da postare un esempio anche errato del mio codice in ce un memory leak?

Comunque scusate, non sono alle prime con la programmazione, è il capitolo delle allocazioni e puntatori che riserva sempre qualche dubbio e dove mi fate notare che sbaglio. Percio un esempio dove sbaglio e la correzione sono ben accetti.

Non lo faccio solo per sport o per compitino, mi serviranno per creare il software che usano le tabelle.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Figurati, quello va bene ci mancherebbe. È che se non ti sono chiarissimi i puntatori, andare a guardare i puntatori di puntatori che puntano a char non è il massimo.

Comunque hai un memory leak quando sei in questa situazione: allocchi memoria (malloc/calloc) e perdi il puntatore a quella locazione. In questo caso lo perdi perché vai a porre a Null la locazione, ma anche nel codice del precedente topic (quando assegnavi la stringa a "line") perdevi il puntatore alla memoria precedentemente allocata.
In questo caso si configura un memory leak: hai memoria allocata che non sarà più acceduta, perché non hai più un puntatore. Quindi la memoria rimarrà allocata sino al termine del processo, non potendo fare un free su di essa.

Ps. Sono sempre da smartphone, non riesco a fare esempi, ma il codice che ho quotato li sopra è già uno
 
  • Mi piace
Reazioni: Andretti60

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
C:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int **ptrarrayofarray;
    int i,l;

    int *ptrarray;

    //il primo puntatore ** è collegato ad un array di puntatori interi
    //ciascun puntatore dell'array interi fa riferimento ad un sottoinsieme di un array fisso

    ptrarrayofarray = (int **)malloc(3 * sizeof(int *));
    int array[3*5];

    for(i = 0; i < 3; i++)
        ptrarrayofarray[i] = (int *)calloc(5,sizeof(int *));

    //iniializzo tutti i campi
    for(i = 0;i < 3 * 5; i++)
        array[i] = 0;

    array[0] = 0;
    array[1] = 1;
    array[2] = 2;
    array[3] = 3;
    array[4] = 4;
    array[5] = 5;
    array[7] = 7;

[B]    ptrarrayofarray[0] = &array[0];

    ptrarrayofarray[1] = &array[5];

    ptrarrayofarray[2] = &array[10];[/B]

    for(i = 0; i < 3; i++)
        for(l = 0; l < 5; l++)
            if(l >= 5 - 1)
                printf("%d\t\n",ptrarrayofarray[i][l]);
            else
               printf("%d\t",ptrarrayofarray[i][l]);

    //ora vogliamo ridimensionare il tutto MA COME FACCIO SE array È FISSO?
    printf("Hello world pointers!\n");
    return 0;
}

Cosi dovrebbe essere piu chiaro dove i puntatori puntano.

Ora voglio ridimensionare il tutto.
La domanda: COME FACCIO SE array E' FISSO? mettiamo che non lo voglio piu lungo 3*5 interi, ma 6*7 cioè ho aggiunto 3 righe e 2 colonne.
Devo popolarlo con i nuovi dati ma l'array è statico. Allora posso provare a copiare gli elementi da array lasciando i buchi.

C:
int tmparray[6*7];

int e = 0;
for (i = 0; i <  totnumrows; i ++)
      for(l = 0; l < totnumcols; l++)
      {
             if(l > numcols) tmparray[e] = 0;
             else tmparray[e] = array[e];
             e++;
      }
 
Ultima modifica:
U

Utente cancellato 371741

Ospite
per memory leak se sei in linux, che per esperimenti C ti consiglio vivamente, usa valgrind.


se un array e' statico, e' statico. punto.

Fallo dinamico, e poi per ridimensionare butta l'occhio a

realloc/reallocarray
 
Ultima modifica da un moderatore:
  • Mi piace
Reazioni: BigIssue

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
Prima o poi capirò meglio i puntatori.
Cosi dovrebbe essere giusto, raggiunge l'intento: creare un array fisso ma specificando la dimensione durante l'esecuzione del programma.


C:
    ptrarray = (int *)calloc(3*5,sizeof(int));
    ptrarray[0] = 0; //ptrarray è gia un puntatore all'array fisso
    ptrarray[1] = 1;
    ptrarray[2] = 2;
    ptrarray[3] = 3;
    ptrarray[4] = 4;
    ptrarray[5] = 5;
    ptrarray[7] = 7;

    for(i = 0; i < 3*5; i++)
    {
        printf("ptrarray:%d\n",ptrarray[i]);
    }

    //se faccio la free ptrarray realmente è sbagliato perchè ptrarray
    //è il puntatore alla prima cella di un array fisso.
    //se faccio la free su ciascun elemento è sbagliato perchè l'array è fisso

    //in sostanza questo programma serve a creare in esecuzione un array di dimensione n.

    //ora vogliamo ridimensionare il tutto
    //quindi ridimensiono ptrarray che a sua volta era dinamico
    //e ottengo il puntatore ad un nuovo array di dimensione 6*7
    //i vecchi valori non li perdo perchè vengono copiati nel nuovo quando crea il nuovo array
    tmptrarray = (int *)realloc(ptrarray,6*7 * sizeof(int));
    tmptrarray[6]  = 6;
    tmptrarray[12] = 12;
    tmptrarray[22] = 22;
    tmptrarray[40] = 40;

    for(i = 0; i < 6 * 7; i++)
    {
        printf("tmptrarray:%d\n",tmptrarray[i]);
    }

Spero di non avere stufato. Di certo si un pochino.
 
U

Utente cancellato 371741

Ospite
No non hai stufato, ma impressione e' che il tuo sia cargo-cult,


Ovvero, voler per forza usare determinate tecniche anche se non sono
necessarie.
Consiglio, usa le tecniche quando servono a fronte di un progetto
fatto prima, design che va a risolvere determinati problemi precisi.

Codice:
ptrarray = (int *)calloc(3*5,sizeof(int));

Allochi un array di 15 int , non si usano mai numeri hardcoded
ma piuttosto dei define che fanno capire qual'era il significato dietro
a quei numeri.

Codice:
for(i = 0; i < 3*5; i++)

inizializzi 7 valori, e ne leggi 15, nelle caselle non
inizializzate leggerai immondizia

boh, poi si il realloc funzionera', ma veramente non si
capisce il tuo intento.
 
  • Adoro
Reazioni: Andretti60

BigIssue

Utente Attivo
221
18
CPU
intel dual core n3050
Scheda Madre
asus x540s
RAM
4gb
GPU
intel HD
OS
Windows 10
boh, poi si il realloc funzionera', ma veramente non si
capisce il tuo intento.
Si è un po pasticciato. ma si capisce di piu essendo che imposto gli indirizzi con l'operatore & unario. Vanno messe le define e inizializzato nei campi che non utilizzo dell'array. Dovrei avere meno dubbi sui puntatori.
 

Andretti60

Utente Èlite
6,440
5,091
Prima o poi capirò meglio i puntatori.
Cosi dovrebbe essere giusto, raggiunge l'intento: creare un array fisso ma specificando la dimensione durante l'esecuzione del programma.


C:
    ptrarray = (int *)calloc(3*5,sizeof(int));
    ptrarray[0] = 0; //ptrarray è gia un puntatore all'array fisso
    ptrarray[1] = 1;
    ptrarray[2] = 2;
    ptrarray[3] = 3;
    ptrarray[4] = 4;
    ptrarray[5] = 5;
    ptrarray[7] = 7;
    //se faccio la free ptrarray realmente è sbagliato perchè ptrarray
    //è il puntatore alla prima cella di un array fisso.
    //se faccio la free su ciascun elemento è sbagliato perchè l'array è fisso

Spero di non avere stufato. Di certo si un pochino.
Non stai stufando, qui il problema è che stai cercando di scrivere codice usando i puntatori 1) senza averli studiati 2) senza avere studiato la allocazione dinamica della memoria. Ti sono arrivati i libri, come ti hai detto. Bene. Spegni il computer, e studiali, magari facendo SOLO gli esercizi raccomandati, altrimenti non impari un bel nulla. Credimi, insegnai linguaggio C nei corsi di laboratorio all’uni, ne ho visti di gente come te carica di entusiasmo a cui ho vietato l’accesso ai terminali finché non avessero dimostrato di avere studiato la teoria.
Prendi il commento che hai scritto nel codice sopra, non ha senso alcuno. Ptarray NON È il puntatore alla prima cella di un array FISSO. E NON puoi fare il FREE dei singoli elementi perché non sono MAI stati allocati.
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili