Stringo la stringa fino alla fine della stringa.....

Di recente sto giocherellando con la gestione di testi, riconoscimento di pattern e cose simili
spesso mi capita di dover creare delle stringhe (array di caratteri terminati da 0)
e trovo due problemi

  1. se sono locali e non globali sono spesso “sporchi”, vengono inizializzati a zero solo se sono globali
  2. se globali sono inizializzati a 0, che significa fine stringa
    insomma sono sempr costretto, che anchesì uso molto le variabili locali, dicevo sono costretto a scrivere mille volte
char nome[dimensione];
for (byte i=0; i<dimensione; nome[i++]=0);
nome[dimensione]=0;

e non ditemi che esiste la memset, non credo che sia più veloce di una for a byte, forse è proprio una for a byte
ma la mia ambascia non è il tempo di esecuzione, nemmeno quello di compilazione, è proprio la scrittura, che dopo le 22 diventa piena di errori
quindi stasera, dopo che mi son girate le sfere una volta di troppo ho inventato una simpatica macro

#define stringa(nome, dimensione) char nome[dimensione]; for (byte i = 0; i < dimensione; nome[i++] = ' '); nome[dimensione-1] = 0;

una macro che crea una variabile array di caratteri lunga “dimensione” e chiamata “nome”
per provarla ho fatto questo:

// di Nelson "StandardOil"
// Idea da sviluppare: prova macro di stringa

#define stringa(nome, dimensione) char nome[dimensione]; for (byte i = 0; i < dimensione; nome[i++] = ' '); nome[dimensione-1] = 0;
void setup(void)
{
    Serial.begin(9600);
    stringa(addendo, 22)
    stringa(risultato, 5);
    Serial.print(strlen(addendo));
    Serial.print('-');
    Serial.print(addendo);
    Serial.println('-');
    Serial.print(strlen(risultato));
    Serial.print('-');
    Serial.print(risultato);
    Serial.println('-');
    Serial.println("finito");
}

void loop(void)
{
}

notare che si puo’ richiamare con o senza il punto e virgola, in realtà essendo una macro se ne frega
attenzione che E’ una macro, quindi occhio agli effetti collaterali (non usate operatori di pre e post incremento, per esempio), e al fatto che NON è uno statement (costrutto, in italiano costrutto) singolo, quindi occhio se la usate in un ciclo…
io me la metto adesso nella mia libreria nelson.h

Per inizializzare a zero array locali mi sembra che basti scrivere cosi ...

void loop(){

char localArray[10]={0};


}

È normale che vengano inizializzate a 0 solo se globali, questo vale per tutte le variabili e lo dice lo standard C.

Che memset() sia più veloce del tuo ciclo è probabile. Devi sempre assumere che una funzione di libreria è superottimizzata e molto furba nel gestire tutti i corner cases.

Ma, in realtà, quel che fai serve raramente. La maggior parte delle volte basta inizializzare a 0 solo il primo carattere della stringa. Visto che lo 0 è il terminatore, di fatto la stringa è vuota se arriva subito e, se la vai a manipolare con le funzioni standard, la considereranno tale. Funzionano tutte partendo da sinistra, facendo quel che devono fare sul carattere e fermandosi al primo 0.

Qua un esempio di Sensoria in cui aggiungo vari "pezzi" nella stessa stringa in questo modo.

Ho fatto una ricerca, ho letto che se inizializzi solo una parte dell'array i restanti elementi vengono inizializzati a zero.

per cui char array[20]={0}; inizializzo esplicitamente il primo elemento a zero, i successivi non specificati vengono automaticamente portati a zero.

Confermo, ma questo richiede tempo e rallenta quindi l'esecuzione della funzione. Visto che spesso basta inizializzare un singolo elemento, come detto sopra, lo eviterei.

Vorrei fare un po’ di chiarezza:

  1. lo sapevo, e lo ho scritto, che dichiarare una variabile globale inizializza a zero la variabile, sapevo anche che lo dicevano ancora Brian e Dennis
  2. mi ero in effetti dimenticato che inizializzare solo parzialmente un array in dichiarazione mette a zero la parte non inizializzata, anche se si tratta di array locali, anche questo sta in effetti scritto nel K&R
  3. che la memset sia probabilemnte più veloce di un ciclo for locale, sì, ci sta, ma non vado certo a fare le prove
    perche? perche la cosa non mi interessa!
    la parte interessante (spero) del mio post NON è la “meccanica” della dichiarazione di array locali di caratteri
    è l’uso di una macro per semplificare la SCRITTURA della dichiarazione
    comunque inizializzare a zero il primo elemento dell’array non mi interessa, perchè così facendo la funzione strlen() mi restituirebbe un valore erroneo, ovvero non avrei maiera per sapere, una volta passata la stringa come argomento, di saperne la lunghezza allocata

a parziale correzione di quello che ho scritto nel mio primo post debbo dire che non serve preoccuparsi degli effetti collaterali negli argomenti della macro, dato che debbono essere delle costanti
anche usare la macro in un ciclo for avrebbe poco scopo, dato che creerebbe un array LOCALE al solo for
per puro masochismo ho provato a fare una cosa del genere

    for (char nom = 'a'; nom < 'c'; nom++)
    {
        char nomestringa[] = " ";
        strcpy(nomestringa, nom);
        stringa(nomestringa, 10)
    }

come prevedevo NON crea 3 array di nome a, b, c, ma è stato interessante provare…

Secondo me', se continui a seviziarla cosi, la tua stringa salta fuori dal PC, ti "stringe" in un'angolo e ti prende a "stringate" finche' non la liberi ... :stuck_out_tongue: ... (scusa, non ho resistito :D)

Standardoil:
3) che la memset sia probabilemnte più veloce di un ciclo for locale, sì, ci sta, ma non vado certo a fare le prove
perche? perche la cosa non mi interessa!

Concordo, ma tieni presente quanto detto come criterio generale. Molte funzioni di libreria sono scritte direttamente in assembly, per cui probabilmente saranno più veloci. Nella maggior parte dei casi è meglio utilizzare quel che già c’è piuttosto che reinventare la ruota.

Standardoil:
comunque inizializzare a zero il primo elemento dell’array non mi interessa, perchè così facendo la funzione strlen() mi restituirebbe un valore erroneo, ovvero non avrei maiera per sapere, una volta passata la stringa come argomento, di saperne la lunghezza allocata

Qua c’è un errore concettuale: strlen() non serve a sapere quanto è grande la stringa nel senso di quanti caratteri può contenere (cioé quanto grande è stata allocata), bensì quanti ce ne sono dentro al momento. Inizializzando il primo carattere a 0 strlen() ritornerà 0, correttamente. La dimensione allocata è una cosa di cui devi tenere traccia tu, il C non prevede nessun meccanismo automatico per farlo (chiariamo subito: sì, sizeof() funziona se hai un array, ma se hai il puntatore ad esso, non dà il risultato che ti aspetteresti). Per capirci: se anche hai un char pippo[1000]; e fai strcpy (pippo, “ciao”), strlen(pippo) ritornerà 4.

    for (char nom = 'a'; nom < 'c'; nom++)
    {
        char nomestringa[] = " ";
        strcpy(nomestringa, nom);
        stringa(nomestringa, 10)
    }

Qui non capisco bene, cosa volessi fare, ma c’è un altro errore: strcpy() prende come parametri delle stringhe, ovvero array terminati da 0. Tu gli stai passando nom che è un sigolo byte, per cui la strcpy() continuerà a copiare finché non troverà casualmente uno 0 nei byte successivi, overflowando nomestringa. Per di più, abituati fin da subito a usare strncpy() (e tutte le sorelle con una ‘n’ nel nome), per limitare i danni (anche se ci sarebbe ancora da dire su questo, vedi strlcpy()).

SukkoPera:
Qua c'è un errore concettuale: strlen() non serve a sapere quanto è grande la stringa nel senso di quanti caratteri può contenere (cioé quanto grande è stata allocata), bensì quanti ce ne sono dentro al momento. Inizializzando il primo carattere a 0 strlen() ritornerà 0, correttamente. La dimensione allocata è una cosa di cui devi tenere traccia tu, il C non prevede nessun meccanismo automatico per farlo (chiariamo subito: sì, sizeof() funziona se hai un array, ma se hai il puntatore ad esso, non dà il risultato che ti aspetteresti). Per capirci: se anche hai un char pippo[1000]; e fai strcpy (pippo, "ciao"), strlen(pippo) ritornerà 4.

la cosa che ho fatto non è stupida come sembra
io creo un buffer e lo passo ad una funzione di lettura da file (o altro stream, in futuro)
inizializzare a "non vuoto" il buffer mi permette di evitare di dover passare come argomento ANCHE la lunghezza, perchè la lunghezza la faccio calcolare alla funzione chiamata
certo, se conoscessi a priori le dimensioni, oppure se volessi passare un argomento in più....
ma siccome le dimensioni cambiano caso per caso, e non voglio passare argomenti inutili...
che strllen() mi restituisca 4 dopo aver scritto ciao nella stringa è pacifico, io voglio che PRIMA di cominciare ad aprire file in giro sono sicuro di avere buffer adeguati, costa poco in termini computazionali, e mi "para la schiena" da errori

A parte che non ho capito come pensi di calcolare la dimensione del buffer, pensi che calcolarla sia più veloce che passarla come parametro? E allora perché pensi che strncpy() e compagnia, nonché qualunque API di qualunque libreria si facciano passare la dimensione dei buffer?

bah....
non capisco il problema
io ho solo indicato una scorciatoia
se non vi va non usatela, ma mi scoccia alla grande sentirmi sparare addosso dopo aver condiviso un (piccolo) risultato
Non ho mai detto che calcolare una dimensione sia più rapido che passarla come parametro, te lo sei inventato tu, tientelo....
io ho solo detto che NON VOGLIO passare un parametro in piu' che considero non necessario
tu vuoi farlo? io NON TI HO MAI criticato
devo seguire il tuo esempio?

Se la moderazione volesse chiudere questo topic io ne sarei grato.

Non ti preoccupare, non risponderò mai più a un tuo thread.

Non litigate, per favore ... le incomprensioni e le differenze di opinioni sono sacrosante, ed a volte possono portare anche a discussioni interessanti, non c'e' motivo secondo me di farne una guerra :wink:

Per evitare scarne polemiche ed inutili discussioni, chiudo il thread.

Vorrei però segnalare al OP che, quando si illustra/si propone una propria soluzione, si deve essere pronti ad accettare tutte le critiche ed i suggerimenti, altrimenti ... è meglio tenersi per se il proprio lavoro e non aprirci un thread.

Guglielmo