C
Meine Hausaufgabe ist es, eine Schnur zu nehmen und sie bei jeder neuen Zeile in Stücke zu teilen. Ich habe keine Ahnung, was ich tun soll! Bitte helfen Sie!
Schwieriges Problem für einen C-Programmierkurs! Zunächst müssen Sie einige Grundlagen zu diesem komplizierten Thema verstehen.
Eine Zeichenfolge besteht nur aus Zeichen . Dies bedeutet, dass Programmierer eine spezielle Folge von Zeichen verwenden müssen, um eine "unsichtbare" Sache anzuzeigen (das ist kein Leerzeichen, das als Zeichen zählt), um diese unsichtbare Sache zu bezeichnen.
Unter Windows ist die neue Zeile eine Folge von zwei Zeichen in der Zeichenfolge: Backslash und n (oder die Zeichenfolge "\n"
)
Auf Linux- oder OS / X-Macs ist dies eine Folge von vier Zeichen: Backslash, n, Backslash und dann r: (oder "\n\r"
).
(Interessanter historischer Hinweis: Auf älteren Macintosh-Rechnern war es eine andere Folge von vier Zeichen: "\ r \ n" ... ganz anders als unter Unix! Die Geschichte geht seltsame Wege.)
Es mag den Anschein haben, dass Linux verschwenderischer ist als Windows, aber es ist eine bessere Idee, eine längere Sequenz zu verwenden. Da Windows eine so kurze Sequenz verwendet, kann die C-Laufzeit die tatsächlichen Buchstaben nicht \n
ohne spezielle Systemaufrufe ausdrucken . Sie können in der Regel auf Linux tun , ohne einen Systemaufruf (es kann sogar drucken \n\
oder \n\q
... alles andere als \n\r
). Da C jedoch plattformübergreifend sein soll, wird der kleinste gemeinsame Nenner erzwungen. So werden Sie immer \n
in Ihrem Buch zu sehen.
(Hinweis: Wenn Sie sich fragen, wie wir reden, \n
ohne jedes Mal neue Zeilen zu erhalten, ist StackOverflow fast vollständig in HTML geschrieben ... nicht in C. Es ist also viel moderner. Viele dieser alten Aspekte von C sind Sie werden von Dingen angesprochen, von denen Sie vielleicht gehört haben, wie CLANG und LLVM.)
Aber zurück zu dem, woran wir arbeiten. Stellen wir uns eine Saite mit drei Stücken und zwei Zeilenumbrüchen vor:
"foo\nbaz\nbar"
Sie können sehen, dass die Länge dieser Zeichenfolge 3 + 2 + 3 + 2 + 3 = 13 ist. Sie müssen also einen Puffer mit der Länge 13 erstellen , und C-Programmierer fügen aus Sicherheitsgründen immer einen zur Größe ihrer Arrays hinzu. Machen Sie also Ihren Puffer und kopieren Sie den String hinein:
/* REMEMBER: always add one to your array sizes in C, for safety! */
char buffer[14];
strcpy(buffer, "foo\nbaz\nbar");
Nun müssen Sie nach dem zweistelligen Muster suchen, das die neue Zeile darstellt. Sie sind nicht zu suchen erlaubt nur einen Schrägstrich. Da C häufig zum Teilen von Strings verwendet wird, wird beim Versuch eine Fehlermeldung ausgegeben. Sie können dies sehen, wenn Sie versuchen zu schreiben:
char pattern[2];
strcpy(pattern, "\");
(Hinweis: Im Compiler gibt es eine Einstellung für Programme, die nur nach Backslashes suchen. Dies ist jedoch äußerst selten. Backslashes werden sehr selten verwendet, weshalb sie für diesen Zweck ausgewählt wurden. Wir werden das nicht ändern einschalten.)
Lasst uns also das Muster erstellen, das wir wirklich wollen:
char pattern[3];
strcpy(pattern, "\n");
Wenn wir zwei Zeichenfolgen mit einer bestimmten Länge vergleichen möchten, verwenden wir strncmp
. Es vergleicht eine bestimmte Anzahl von Zeichen einer möglicherweise größeren Zeichenfolge und gibt an, ob sie übereinstimmen oder nicht. So strncmp("\nA", "\nB", 2)
gibt 1 (true). Dies ist auch dann der Fall, wenn die Zeichenfolgen über die Länge von drei nicht ganz gleich sind ... sondern nur zwei Zeichen sein müssen.
Also lassen Sie sich Schritt für Schritt durch unsere Puffer, ein Zeichen zu einem Zeitpunkt, die Suche nach den zwei Zeichen Matchs zu unserem Muster. Jedes Mal, wenn wir eine zweistellige Folge eines Backslashs, gefolgt von einem n, finden, verwenden wir den speziellen Systemaufruf (oder "syscall") putc
, um eine spezielle Art von Zeichen auszulesen : ASCII-Code 10 , um eine physikalische Newline zu erhalten .
#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;
}
Die Ausgabe dieses Programms ist das gewünschte Ergebnis ... der String-Split!
foo
baz
bar
\t
ist für \ trolling ...
Absolut falsch von oben nach unten. Doch voller plausibel klingender Unsinn, der Informationen wie das, was im Lehrbuch oder in Wikipedia steht, durcheinandergebracht hat. Die Programmlogik erscheint im Kontext der Fehlinformation transparent, ist aber völlig irreführend. Sogar globale Variablen und die Rückgabe eines Fehlercodes ...
...
Natürlich gibt es nur ein Zeichen in der C-String-Darstellung der zweistelligen Quellliteralsequenz \n
. Das Vergrößern eines Puffers ist jedoch harmlos, solange strlen()
die tatsächliche Länge für die Operation verwendet wird.
...
Wir versuchen, den Leser davon zu überzeugen, dass strncmp
es sich um eine boolesche Operation handelt, die entweder mit (1) übereinstimmt oder nicht (0) übereinstimmt. Tatsächlich hat es jedoch drei Rückgabewerte (-1 für weniger, 0 für gleich, 1 für mehr) . Unser zweistelliges "Muster", das verglichen wird, ist nicht [ \
, n
], sondern [ \n
, \0
] ..., das den impliziten Nullterminator aufgreift. Da diese Sequenz durch die Zeichenfolge gleitet, ist sie niemals größer als eine zweistellige Sequenz, mit der sie verglichen wird. Bestenfalls ist sie Null, wenn die Eingabezeichenfolge eine abschließende neue Zeile enthält.
...
Alles, was Sie tun müssen, ist, die Zeichenfolge zu durchlaufen und Zeichen für Zeichen zu drucken. Der oberste Zweig läuft nie. (Obwohl Sie es schaffen könnten, wenn Ihre Zeichenfolge niedriger als die darin enthaltenen \n
Codes wäre, sagen Sie tab ..., um auf mysteriöse Weise Zeichen aus der Ausgabe auszulassen :-P)