DOMANDA stringhe e puntatori in C

cuttyflam

Nuovo Utente
18
2
Sto iniziando a studiare il linguaggio C.
Il mio testo di riferimento dice che il nome di una stringa è un puntatore
e che quindi è possibile fare questa uguaglianza p(con variabile char *p)=s(stringa) e non p=&s.
La domanda è questa.
Se con p+i riesco ad accedere a tutti gli indirizzi di s questo vuol dire che la stringa e quindi anche un file di testo... viene memorizzata in memoria in indirizzi successivi, non in modo frammentato?
 

_Achille

Utente Èlite
3,065
722
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
Hard Disk
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
Scheda Video
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
Alimentatore
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
Sistema Operativo
Windows 10 Pro
Una stringa un file di testo??!

Una stringa in C è un array di char terminato da un '\0', ossia risiede nella memoria volatile e non ha altre caratteristiche (path, metadati, ecc…) che ha un file di testo.

Con p + i non accedi a tutti gli indirizzi di s, ma all’i-esimo elemento della stringa (o anche a zone fuori dalla stringa…).

L’ assegnazione è possibile perché gli array possono implicitamente decadere in puntatori in alcuni casi, e questo è uno di quelli.

Un altro, ad esempio, è quello di un argomento in una funzione.
C:
void f(char s[]);
void f(char s[10]);
void f(char *s);
Sono tutte dichiarazioni equivalenti che decadono nell’ultimo caso.

Un caso, invece, in cui non avviene il cast implicito a puntatore è con l’operatore sizeof.

Inoltre l’operatore [] funziona esattamente come l’aritmetica dei puntatori, quindi s[i] è equivalente a *(p + i) e quindi a p[i].
 
Ultima modifica:

cuttyflam

Nuovo Utente
18
2
Una stringa un file di testo??!

Una stringa in C è un array di char terminato da un '\0', ossia risiede nella memoria volatile e non ha altre caratteristiche (path, metadati, ecc…) che ha un file di testo.

Con p + i non accedi a tutti gli indirizzi di s, ma all’i-esimo elemento della stringa (o anche a zone fuori dalla stringa…).

Questo è possibile perché gli array possono implicitamente decadere in puntatori in alcuni casi, e questo è uno di quelli.

Un altro, ad esempio, è quello di un argomento in una funzione.
C:
void f(char s[]);
void f(char s[10]);
void f(char *s);
Sono tutte dichiarazioni equivalenti che decadono nell’ultimo caso.

Un caso, invece, in cui non avviene il cast implicito a puntatore è con l’operatore sizeof.
Grazie per la sua risposta.
In un programma in ambiente dos, ad esempio, potrei dare in input invece di una stringa da battere al terminale un intero file di testo digitando eseguibile(file.exe) < textfile(nome del file di testo). In pratica il file di testo diventa la mia stringa caricata in memoria. Da qui la mia domanda. Questa stringa, anche molto lunga, è caricata in memoria in indirizzi adiacenti, non frammentati?
 

_Achille

Utente Èlite
3,065
722
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
Hard Disk
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
Scheda Video
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
Alimentatore
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
Sistema Operativo
Windows 10 Pro
Grazie per la sua risposta.
In un programma in ambiente dos, ad esempio, potrei dare in input invece di una stringa da battere al terminale un intero file di testo digitando eseguibile(file.exe) < textfile(nome del file di testo). In pratica il file di testo diventa la mia stringa caricata in memoria. Da qui la mia domanda. Questa stringa, anche molto lunga, è caricata in memoria in indirizzi adiacenti, non frammentati?
Tu vuoi dare come argomento il path al file di testo?
Troverai quell’argomento nell’array di stringhe argv alla posizione n. 1.

Quella è una stringa, con tutte le sue caratteristiche
 

cuttyflam

Nuovo Utente
18
2
Non c'entra il path. Con quel comando da terminale il programma legge esclusivamente i caratteri del file e li memorizza nel formato richiesto dal programma(come una successione di char oppure come una stringa).
 

_Achille

Utente Èlite
3,065
722
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
Hard Disk
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
Scheda Video
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
Alimentatore
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
Sistema Operativo
Windows 10 Pro
Non c'entra il path. Con quel comando da terminale il programma legge esclusivamente i caratteri del file e li memorizza nel formato richiesto dal programma(come una successione di char oppure come una stringa).
Scusami eh, e come accederesti al file dal programma? Cosa fornisci come argomento?
 

cuttyflam

Nuovo Utente
18
2
Mettiamo che il compilatore generi un programma es_1.exe da un file es_1.c e che nella stessa directory esista un file di testo di nome testo_1.txt.
Dando da terminale il comando es_1 < testo_1.txt il sistema operativo dos da in input al programma numeri, caratteri o stringhe contenute nel file testo_1.txt. Testato personalmente con la funzione scanf. Il mio scanf normalmente legge dati da tastiera, ma dando quel comando(es_1 < testo_1.txt) esternamente(sull'eseguibile) legge i dati dal file.
 

_Achille

Utente Èlite
3,065
722
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
Hard Disk
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
Scheda Video
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
Alimentatore
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
Sistema Operativo
Windows 10 Pro
Quindi "testo_1.txt" è su argv[2] ed è un path, relativo, al file.
 

cuttyflam

Nuovo Utente
18
2
Figurati che non ancora studio i parametri da passare ad un programma in C. Non so nemmeno cosa sia argv. Fa prima se si legge la pag.24 di Al Kelley e Ira Pohl 'C Didattica e Programmazione' 4°edizione.
 
Ultima modifica:

_Achille

Utente Èlite
3,065
722
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
Hard Disk
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
Scheda Video
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
Alimentatore
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
Sistema Operativo
Windows 10 Pro
Figurati che non ancora studio i parametri da passare ad un programma in C. Non so nemmeno cosa sia argv. Fa prima se si legge la pag.24 di Al Kelley e Ira Pohl 'C Didattica e Programmazione' 4°edizione.
Non darmi del lei 😅

Non ho ancora capito quello che devi fare, quello che vuoi fare e cosa hai studiato di C.
Se riesci allega il testo dell’esercizio.
 

DispatchCode

Utente Attivo
793
506
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Internet
30Mbps/3Mbps con Eolo
Sistema Operativo
Windows 10 64bit
Mi sa che stai mettendo assieme un pò di cose...

Ciò di cui stai parlando è <, che ti consente di redirezionare lo standard input.
Quindi se fai una cosa come questa:

C:
#include <stdio.h>

int main() {
    char str[10] = {0};
    scanf("%s", str);
    printf("String: %s", str);
    return 0;
}
e lo esegui in questo modo es.exe < es.txt, vedrai il contenuto del file.

Quindi...
Se con p+i riesco ad accedere a tutti gli indirizzi di s questo vuol dire che la stringa e quindi anche un file di testo... viene memorizzata in memoria in indirizzi successivi, non in modo frammentato?
Non ho ben capito che vuoi dire.
La stringa non è un file di testo, come diceva Achille. E tu non stai accedendo ad un file, in quanto la scanf() - in quel caso - invece che attendere il tuo input da tastiera, risente della redirezione. Infatti se prima del return metti un "getchar()", vedrai tu stesso che il programma terminerà senza attendere.

Cambiando il codice in questo modo:
C:
#include <stdio.h>

int main() {
    char str[10] = {0};
    scanf("%s", str);

    printf("String: %s", str);
    
    freopen("CON", "r", stdin);
    getchar();
  
    return 0;
}
torni ad utilizzare la keyboard come stdin.
 
  • Mi piace
Reactions: BAT00cent e Mursey

cuttyflam

Nuovo Utente
18
2
Ciò di cui stai parlando è <, che ti consente di redirezionare lo standard input.
Quindi se fai una cosa come questa:

C:
#include <stdio.h>

int main() {
    char str[10] = {0};
    scanf("%s", str);
    printf("String: %s", str);
    return 0;
}
e lo esegui in questo modo es.exe < es.txt, vedrai il contenuto del file.
Corretto, il contenuto del file viene quindi memorizzato nella variabile stringa str.
La mia domanda è: la stringa, che può essere molto grande per l'appunto, viene memorizzata in uno spazio di memoria continuo, non frammentato come avviene comunemente la memorizzazione sugli hard disk, con pezzi di file da una parte e pezzi dall'altra?
Mi spiego meglio. Se un puntatore p ha lo stesso indirizzo di una stringa str, p+i mi darà lo stesso indirizzo di str di i(non riesco a mettere le quadri) per ogni i che appartiene alla lunghezza della stringa? La stringa infatti potrebbe essere indicizzata come avviene per gli hard disk, ma il puntatore p non conoscerebbe questa indicizzazione della stringa. La mia domanda in pratica nasce perché sono un assiduo deframmentatore di hard disk.
 

theprogrammer.99

Nuovo Utente
80
22
La domanda non ha molto senso ... la memoria (in questo caso è allocata nello stack) ovviamente è contigua. Il file e la deframmentazione non c'entrano proprio nulla,
 

DispatchCode

Utente Attivo
793
506
CPU
Intel i7 6700HQ, 2.60Ghz, 4 core 8 threads
Scheda Madre
Asustek
Hard Disk
Hitachi 7200 rpm, 1TB
RAM
16GB DDR4 (2 slot su 4)
Scheda Video
Nvidia Geforce GTX 960M, 4GB
Scheda Audio
Realtek
Internet
30Mbps/3Mbps con Eolo
Sistema Operativo
Windows 10 64bit
No aspetta un momento, lascia perdere gli hard disk (che poi dipende da altri fattori ciò che dici, come il file system utilizzato).

Innanzitutto se la stringa è davvero molto grande, non puoi utilizzare lo stack (come ho fatto nel mio esempio), ma dovrai allocare memoria sufficiente (utilizzando malloc/calloc).
La memoria è contigua:

char str[4] = "ciao";
str[0] = 'c';
str[1] = 'i';
str[2] = 'a';
str[3] = 'o';


Allo stesso modo se utilizzi l'aritmetica dei puntatori è uguale.
Anche se allochi memoria nell'heap con calloc/malloc viene allocata memoria virtuale contigua.

Se allochi sullo stack devi creare uno stack grande abbastanza (attenzione perchè c'è un limite... 1MB se non erro, fatto salvo specifiche differenti al momento della compilazione), altrimenti andrai a scrivere in aree di memoria adiacenti.
Usando sempre l'esempio qui sopra: se in str (che è grande 4byte) ne vai a copiare 10, i 6byte in eccesso vanno a sovrascrivere altre aree dello stack (il che significa che potresti sovrascrivere anche delle variabili che hai dichiarato dopo, o altro ancora). Diciamo che sei fortunato quando crasha, perchè diversamente è difficile trovare l'errore...

Le quadre che usi per indirizzare sono solo "zucchero sintattico". E non avviene nessun bounds-checking; se scrivi *(str+100), verrà calcolato l'indirizzo str+100.

Diciamo che l'indirizzo virtuale di str è 0x1234.
Codice:
str[0] è uguale a *(str+0) -> 0x1234 + 0 = 0x1234
str[1] è uguale a *(str+1) -> 0x1234 + 1 = 0x1235
...
a basso livello infatti avviene una cosa come questa:
[str + (i * sizeof(char))]


Inutile comunque dire che è un modo scorretto per leggere da file (quello che stai utilizzando). Devi ottenere un handle al file e leggerne il contenuto.
 

cuttyflam

Nuovo Utente
18
2
La domanda non ha molto senso ... la memoria in questo caso è allocata nello stack e ovviamente è contigua. Il file e la deframmentazione non c'entrano proprio nulla,
Quindi in memoria i dati(tutto ciò che viene caricato in memoria?) si memorizzano in spazi contigui. Non lo sapevo. Grazie.
Post automaticamente unito:

No aspetta un momento, lascia perdere gli hard disk (che poi dipende da altri fattori ciò che dici, come il file system utilizzato).

Innanzitutto se la stringa è davvero molto grande, non puoi utilizzare lo stack (come ho fatto nel mio esempio), ma dovrai allocare memoria sufficiente (utilizzando malloc/calloc).
La memoria è contigua:

char str[4] = "ciao";
str[0] = 'c';
str[1] = 'i';
str[2] = 'a';
str[3] = 'o';


Allo stesso modo se utilizzi l'aritmetica dei puntatori è uguale.
Anche se allochi memoria nell'heap con calloc/malloc viene allocata memoria virtuale contigua.

Se allochi sullo stack devi creare uno stack grande abbastanza (attenzione perchè c'è un limite... 1MB se non erro, fatto salvo specifiche differenti al momento della compilazione), altrimenti andrai a scrivere in aree di memoria adiacenti.
Usando sempre l'esempio qui sopra: se in str (che è grande 4byte) ne vai a copiare 10, i 6byte in eccesso vanno a sovrascrivere altre aree dello stack (il che significa che potresti sovrascrivere anche delle variabili che hai dichiarato dopo, o altro ancora). Diciamo che sei fortunato quando crasha, perchè diversamente è difficile trovare l'errore...

Le quadre che usi per indirizzare sono solo "zucchero sintattico". E non avviene nessun bounds-checking; se scrivi *(str+100), verrà calcolato l'indirizzo str+100.

Diciamo che l'indirizzo virtuale di str è 0x1234.
Codice:
str[0] è uguale a *(str+0) -> 0x1234 + 0 = 0x1234
str[1] è uguale a *(str+1) -> 0x1234 + 1 = 0x1235
...
a basso livello infatti avviene una cosa come questa:
[str + (i * sizeof(char))]


Inutile comunque dire che è un modo scorretto per leggere da file (quello che stai utilizzando). Devi ottenere un handle al file e leggerne il contenuto.
Non sono in grado di seguirti per ora. Quindi le funzioni malloc e calloc hanno a che fare con la gestione della memoria estesa(è quella che i programmatori chiamano Heap?)?
 

Entra

oppure Accedi utilizzando

Discussioni Simili

Hot del momento