C
Il mio compito a casa è prendere una stringa e dividerla in pezzi in ogni nuova riga. Non ho idea di cosa fare! Per favore aiuto!
Problema complicato per una classe di programmazione C iniziale! Per prima cosa devi capire alcune nozioni di base su questo argomento complicato.
Una stringa è una sequenza composta da soli caratteri . Ciò significa che per consentire ai programmatori di indicare una cosa "invisibile" (che non è uno spazio, che conta come un personaggio), devi usare una sequenza speciale di caratteri per indicare quella cosa invisibile.
Su Windows , la nuova riga è una sequenza di due caratteri nella stringa: barra rovesciata e n (o la stringa "\n"
)
Su Mac Linux o OS / X , è una sequenza di quattro caratteri: barra rovesciata, n, barra rovesciata e quindi r: (o "\n\r"
).
(Interessante nota storica: su Macintoshes più vecchi c'era una sequenza diversa di quattro personaggi: "\ r \ n" ... totalmente indietro rispetto a come Unix ha fatto le cose! La storia prende strade strane.)
Può sembrare che Linux sia più dispendioso di Windows, ma in realtà è un'idea migliore usare una sequenza più lunga. Poiché Windows utilizza una sequenza così breve, il runtime del linguaggio C non può stampare le lettere effettive \n
senza utilizzare chiamate di sistema speciali. Di solito puoi farlo su Linux senza una chiamata di sistema (può persino stampare \n\
o \n\q
... tutt'altro \n\r
). Ma poiché C è pensato per essere multipiattaforma, impone il minimo comune denominatore. Quindi vedrai sempre \n
nel tuo libro.
(Nota: se ti stai chiedendo come stiamo parlando \n
senza ottenere nuove righe ogni volta che lo facciamo, StackOverflow è scritto quasi interamente in HTML ... non C. Quindi è molto più moderno. Molti di questi vecchi aspetti di C sono essere affrontato da cose di cui potresti aver sentito parlare, come CLANG e LLVM.)
Ma torniamo a ciò su cui stiamo lavorando. Immaginiamo una corda con tre pezzi e due nuove linee, come:
"foo\nbaz\nbar"
Puoi vedere che la lunghezza di quella stringa è 3 + 2 + 3 + 2 + 3 = 13. Quindi devi creare un buffer di lunghezza 13 per esso, e i programmatori C ne aggiungono sempre uno alla dimensione dei loro array per sicurezza. Quindi crea il tuo buffer e copia la stringa in esso:
/* REMEMBER: always add one to your array sizes in C, for safety! */
char buffer[14];
strcpy(buffer, "foo\nbaz\nbar");
Ora quello che devi fare è cercare quel modello di due caratteri che rappresenta la nuova riga. Non ti è permesso cercare solo una barra rovesciata. Poiché C viene utilizzato per la suddivisione delle stringhe abbastanza, ti darà un errore se provi. Puoi vedere questo se provi a scrivere:
char pattern[2];
strcpy(pattern, "\");
(Nota: nel compilatore è presente un'impostazione se stai scrivendo un programma che cerca solo barre rovesciate. Ma è estremamente raro; le barre rovesciate vengono utilizzate molto raramente, motivo per cui sono state scelte per questo scopo. accendere.)
Quindi facciamo il modello che vogliamo davvero, in questo modo:
char pattern[3];
strcpy(pattern, "\n");
Quando vogliamo confrontare due stringhe che sono di una certa lunghezza, usiamo strncmp
. Confronta un certo numero di caratteri di una stringa potenzialmente più grande e ti dice se corrispondono o meno. Quindi strncmp("\nA", "\nB", 2)
restituisce 1 (vero). Questo anche se le stringhe non sono del tutto uguali per la lunghezza di tre ... ma perché sono necessari solo due caratteri.
Quindi esaminiamo il nostro buffer, un personaggio alla volta, cercando la corrispondenza dei due personaggi con il nostro modello. Ogni volta che troviamo una sequenza di due caratteri di una barra rovesciata seguita da una n, useremo la speciale chiamata di sistema (o "syscall") putc
per mettere in evidenza un tipo speciale di carattere: il codice ASCII 10 , per ottenere una nuova riga fisica .
#include "stdio.h"
#include "string.h"
char buffer[14]; /* actual length 13 */
char pattern[3]; /* actual length 2 */
int i = 0;
int main(int argc, char* argv[]) {
strcpy(buffer, "foo\nbar\nbaz");
strcpy(pattern, "\n");
while (i < strlen(buffer)) {
if (1 == strncmp(buffer + i, pattern, 2)) {
/* We matched a backslash char followed by n */
/* Use syscall for output ASCII 10 */
putc(10, stdout);
/* bump index by 2 to skip both backslash and n */
i += 2;
} else {
/* This position didn't match the pattern for a newline */
/* Print character with printf */
printf("%c", buffer[i]);
/* bump index by 1 to go to next matchable position */
i += 1;
}
}
/* final newline and return 1 for success! */
putc(10, stdout);
return 1;
}
L'output di questo programma è il risultato desiderato ... la divisione della stringa!
foo
baz
bar
\t
è per \ trolling ...
Assolutamente errato dall'alto verso il basso. Eppure pieno di assurdità dal suono plausibile che ha mescolato informazioni come quelle contenute nel libro di testo o in Wikipedia. La logica del programma appare trasparente nel contesto della disinformazione, ma è completamente fuorviante. Anche variabili globali e restituzione di un codice di errore, per buona misura ...
...
Naturalmente, c'è solo un carattere nella rappresentazione in stringa C della sequenza letterale sorgente di due caratteri \n
. Ma allargare un buffer è innocuo, purché strlen()
venga utilizzato per ottenere la lunghezza effettiva su cui operare.
...
Cerchiamo di convincere il lettore che strncmp
è un'operazione booleana che corrisponde a (1) o no (0). Ma in realtà ha tre valori di ritorno (-1 corrispondenza inferiore, 0 per uguale, 1 per corrispondenza maggiore) . Il nostro "modello" a due caratteri che viene confrontato non è [ \
, n
], ma piuttosto [ \n
, \0
] ... raccogliendo il terminatore null implicito. Poiché quella sequenza scorre attraverso la stringa, non sarà mai maggiore di una sequenza di due caratteri rispetto a ... al massimo sarà zero se nella stringa di input è presente una nuova riga che termina.
...
Quindi tutto ciò che fa è scorrere la stringa e stamparla un carattere alla volta. Il ramo superiore non corre mai. (Anche se potresti ottenerlo se la tua stringa avesse \n
codici inferiori a quelli in essa contenuti, dì tab ... che potrebbe essere usato per omettere misteriosamente i caratteri dall'output :-P)