Linien in Si. Einführung. Arbeiten mit Saiten. String-Klasse. Klassenkonstruktoren. Funktionen Assign(), Append(), Insert(), Replace(), Erase(), Find(), rfind(), Compare(), c_str(). Beispiele

Saiten. Line-Ein-/Ausgang. Formatierte E/A. String-Verarbeitung mit Standardfunktionen der Sprache C. Arbeiten mit Speicher.

1.1. Zeichenketten deklarieren und initialisieren.

Ein String ist ein Array von Zeichen, das mit dem leeren Zeichen '\0' endet. Eine Zeichenfolge wird als normales Zeichenarray deklariert, z. B.

Zeichen s1; // Zeichenfolge neun Zeichen lang

Zeichen*s2; // Zeiger auf Zeichenfolge

Der Unterschied zwischen den Zeigern s1 und s2 besteht darin, dass der Zeiger s1 eine benannte Konstante ist, während der Zeiger s2 eine Variable ist.

Zeichenfolgenkonstanten werden in doppelte Anführungszeichen eingeschlossen, im Gegensatz zu Zeichen, die in einfache Anführungszeichen eingeschlossen werden. Zum Beispiel,

„Das ist eine Schnur.“

Die Länge einer String-Konstante darf laut Standard 509 Zeichen nicht überschreiten. Viele Implementierungen erlauben jedoch längere Zeichenfolgen.

Beim Initialisieren von Strings ist es besser, die Dimension des Arrays nicht anzugeben; der Compiler erledigt dies, indem er die Länge des Strings zählt und eins hinzufügt. Zum Beispiel,

char s1 = „Dies ist ein String.“;

In der Programmiersprache C gibt es für die Arbeit mit Strings große Menge Funktionen, deren Prototypen in den Header-Dateien stdlib.h und string.h beschrieben sind. Die Arbeit mit diesen Funktionen wird in den folgenden Abschnitten besprochen.

1.2. Line-Ein-/Ausgang.

Verwenden Sie die Funktion, um eine Zeichenfolge von der Konsole aus einzugeben

char* bekommt (char*str);

die einen String an die Adresse str schreibt und die Adresse des Eingabestrings zurückgibt. Die Funktion stoppt die Eingabe, wenn sie auf das Zeichen '\n' oder EOF (end of file) stößt. Das Newline-Zeichen wird nicht kopiert. Am Ende der Lesezeile wird ein Null-Byte platziert. Bei Erfolg gibt die Funktion einen Zeiger auf die gelesene Zeile zurück und bei Misserfolg NULL.

Um einen String an die Konsole auszugeben, verwenden Sie die Standardfunktion

int puts (const char *s);

die bei Erfolg eine nicht negative Zahl und bei Fehlschlag EOF zurückgibt.

Die Prototypen der Gets- und Puts-Funktion sind in der Header-Datei stdio.h beschrieben.

#enthalten

printf("Eingabestring: ");

1.3. Formatierte E/A.

Verwenden Sie für formatierte Eingaben von der Konsole die Funktion

int scanf (const char *format, ...);

was die Anzahl der gelesenen Dateneinheiten bei Erfolg und EOF bei Fehler zurückgibt. Der Formatparameter muss auf eine Formatzeichenfolge zeigen, die Eingabeformatspezifikationen enthält. Die Anzahl und die Typen der Argumente, die nach der Formatzeichenfolge folgen, müssen mit der Anzahl und den Typen der Eingabeformate übereinstimmen, die in der Formatzeichenfolge angegeben sind. Wenn diese Bedingung nicht erfüllt ist, ist das Ergebnis der Funktion unvorhersehbar.

Leerzeichen, „\t“- oder „\n“-Zeichen in der Formatzeichenfolge beschreiben ein oder mehrere leere Zeichen im Eingabestrom, die die folgenden Zeichen enthalten: Leerzeichen, '\t', '\n', '\v', '\f'. Die scanf-Funktion überspringt Nullzeichen im Eingabestrom.

Literale Zeichen in einer Formatzeichenfolge, mit Ausnahme des %-Zeichens, erfordern, dass genau dieselben Zeichen im Eingabestrom erscheinen. Wenn es kein solches Zeichen gibt, stoppt scanf die Eingabe. Die scanf-Funktion überspringt wörtliche Zeichen.

Im Allgemeinen lautet die Spezifikation des Eingabeformats:

%[*] [Breite] [Modifikatoren] Typ

Das Zeichen '*' bezeichnet eine Lücke beim Betreten eines durch diese Spezifikation definierten Feldes;

- 'Breite' definiert die maximale Anzahl von Zeichen, die von dieser Spezifikation eingegeben werden;

Der Typ kann folgende Werte annehmen:

c ist ein Zeichenarray,

s – Zeichenfolge, Zeichenfolgen werden durch Leerzeichen getrennt,

d ist eine ganze Zahl mit Vorzeichen bei 10 s/s,

i ist eine ganze Zahl mit Vorzeichen, das Zahlensystem basiert auf den ersten beiden Ziffern,

u ist eine ganze Zahl ohne Vorzeichen in 10 s/s,

o ist eine ganze Zahl ohne Vorzeichen in 8 s/s,

x, X ist eine ganze Zahl ohne Vorzeichen in 16 s/s,

e, E, f, g, G - Gleitkommazahl,

p ist ein Zeiger auf einen Zeiger,

n ist ein Zeiger auf eine ganze Zahl,

[…] ist ein Array gescannter Zeichen, zum Beispiel .

Im letzteren Fall werden nur die in eckige Klammern eingeschlossenen Zeichen aus dem Eingabestrom eingegeben. Wenn das erste Zeichen in eckigen Klammern '^' ist, werden nur die Zeichen eingetragen, die nicht im Array enthalten sind. Der Zeichenbereich eines Arrays wird über das Zeichen '-' angegeben. Bei der Eingabe von Zeichen werden auch führende Leerzeichen und das abschließende Null-Byte des Strings eingetragen.

Modifikatoren können die folgenden Werte annehmen:

h ist eine kurze ganze Zahl,

l, L - Long Integer oder Float,

und werden nur für Ganzzahlen oder Gleitkommazahlen verwendet.

Das folgende Beispiel zeigt Anwendungsfälle für die scanf-Funktion. Beachten Sie, dass dem Formatbezeichner ein Leerzeichen vorangestellt wird, bevor eine Fließkommazahl eingegeben wird.

#enthalten

printf("Gib eine ganze Zahl ein: ");

scanf("%d", &n);

printf("Geben Sie ein Double ein: ");

scanf(" %lf", &d);

printf("Geben Sie ein Zeichen ein: ");

scanf(" %c", &c);

printf("String eingeben: ");

scanf("%s", &s);

Beachten Sie, dass in diesem Programm die Gleitkommazahl initialisiert wird. Dies geschieht, damit der Compiler eine Bibliothek enthält, die das Arbeiten mit Gleitkommazahlen unterstützt. Geschieht dies nicht, kommt es zur Laufzeit bei der Eingabe einer Gleitkommazahl zu einem Fehler.

Verwenden Sie für eine formatierte Ausgabe an die Konsole die Funktion

int printf (const char *format, ...);

die die Anzahl der Ausgabeeinheiten bei Erfolg und EOF bei Misserfolg zurückgibt. Der Formatparameter ist eine Formatzeichenfolge, die Ausgabeformatspezifikationen enthält. Die Anzahl und die Typen der Argumente, die auf die Formatzeichenfolge folgen, müssen mit der Anzahl und den Typen der Ausgabeformatspezifikationen übereinstimmen, die in der Formatzeichenfolge angegeben sind. Im Allgemeinen lautet die Spezifikation des Ausgabeformats:

%[Flags] [Breite] [.Präzision] [Modifikatoren] Typ

- „Flags“ sind verschiedene Symbole, die das Ausgabeformat spezifizieren;

- 'Breite' definiert die Mindestanzahl von Zeichen, die von dieser Spezifikation ausgegeben werden;

- „.precision“ definiert die maximale Anzahl der auszugebenden Zeichen;

- „Modifikatoren“ geben die Art der Argumente an;

- 'Typ' gibt den Typ des Arguments an.

Das folgende Ausgabeformat wird verwendet, um vorzeichenbehaftete Ganzzahlen zu drucken:

%[-] [+ | Leerzeichen] [Breite] [l] d

- – Ausrichtung nach links, standardmäßig – nach rechts;

+ - das Zeichen '+' wird angezeigt, beachten Sie, dass für negative Zahlen immer das Zeichen '-' angezeigt wird;

„Leerzeichen“ – an der Zeichenposition wird ein Leerzeichen angezeigt;

d ist der Datentyp int.

Zur Ausgabe von Ganzzahlen ohne Vorzeichen wird das folgende Ausgabeformat verwendet:

%[-] [#] [Breite] [l]

# - zeigt die anfängliche 0 für Zahlen in 8 c/c oder die anfänglichen 0x oder 0X für Zahlen in 16 c/c an,

l – Modifikator des langen Datentyps;

u ist eine ganze Zahl in 10c/c,

o ist eine ganze Zahl in 8 c/c,

x, X ist eine ganze Zahl in 16 c/c.

Zur Darstellung von Fließkommazahlen wird folgendes Ausgabeformat verwendet:

%[-] [+ | Leerzeichen] [Breite] [.Präzision]

„Präzision“ bezieht sich auf die Anzahl der Stellen nach dem Dezimalkomma für die Formate f, e und E oder die Anzahl der signifikanten Stellen für die Formate g und G. Zahlen werden gerundet. Der Standardwert ist eine Genauigkeit von sechs Dezimalstellen;

f ist eine Festkommazahl,

e ist eine Zahl in Exponentialform, der Exponent wird mit dem Buchstaben "e" bezeichnet,

E ist eine Zahl in Exponentialform, der Exponent wird mit dem Buchstaben "E" bezeichnet,

g ist das kürzeste der f- oder g-Formate,

G ist das kürzeste der f- oder G-Formate.

printf ("n = %d\n f = %f\n e = %e\n E = %E\n f = %.2f", -123, 12.34, 12.34, 12.34, 12.34);

// gibt aus: n = 123 f = 12,340000 e = 1,234000e+001 E = 1,234000E+001 f = 12,34

1.4. Zeichenfolgenformatierung.

Es gibt Varianten der scanf- und printf-Funktionen, die zum Formatieren von Zeichenfolgen entwickelt wurden und sscanf bzw. sprintf heißen.

int sscanf (const char *str, const char *format, ...);

liest Daten aus der durch den str-Parameter angegebenen Zeichenfolge gemäß der durch den format-Parameter angegebenen Formatzeichenfolge. Gibt die Datenmenge zurück, die bei Erfolg gelesen wurde, EOF bei Fehler. Zum Beispiel,

#enthalten

char str = "a 10 1.2 String Keine Eingabe";

sscanf(str, "%c %d %lf %s", &c, &n, &d, s);

printf("%c\n", c); // druckt: a

printf("%d\n", n); // Drucke: 10

printf("%f\n", d); // Drucke: 1.200000

printf("%s\n", s); // druckt: Zeichenkette

int sprintf (char *buffer, const char *format, ...);

formatiert die Zeichenfolge gemäß dem durch den Parameter format angegebenen Format und schreibt das Ergebnis in das Pufferzeichenarray. Die Funktion gibt die Anzahl der in das Pufferzeichenarray geschriebenen Zeichen ohne das abschließende Nullbyte zurück. Zum Beispiel,

#enthalten

char str = "c = %c, n = %d, d = %f, s = %s";

char s = "Dies ist ein String.";

sprintf(puffer, str, c, n, d, s);

printf("%s\n", Puffer); // druckt: c = c, n = 10, d = 1,200000, s = Dies ist ein String

1.5. Konvertieren Sie Zeichenfolgen in numerische Daten.

Die Prototypen der Funktionen zum Konvertieren von Strings in numerische Daten sind in der Header-Datei stdlib.h enthalten, die in das Programm eingebunden werden muss.

Verwenden Sie die Funktion, um eine Zeichenfolge in eine Ganzzahl umzuwandeln

int atoi (const char *str);

char *str = "-123";

n = atoi(str); // n = -123

Verwenden Sie die Funktion, um eine Zeichenfolge in eine lange Ganzzahl umzuwandeln

long int atol (const char *str);

was bei Erfolg die Ganzzahl zurückgibt, in die der String str konvertiert wurde, und 0, wenn es nicht erfolgreich war.

char *str = "-123";

n = atol(str); // n = -123

Verwenden Sie die Funktion, um eine Zeichenfolge in ein Double umzuwandeln

double atof (const char *str);

die im Erfolgsfall eine Gleitkommazahl vom Typ Double zurückgibt, in die der String str umgewandelt wird, und im Fehlerfall 0. Beispiel:

char *str = "-123.321";

n = atof(str); // n = -123.321

Die folgenden Funktionen führen ähnliche Aktionen wie atoi, atol, atof aus, bieten aber mehr Funktionalität.

long int strtol (const char *str, char **endptr, int base);

wandelt den String str in ein long int um, das es zurückgibt. Die Parameter dieser Funktion haben folgenden Zweck.

Wenn das Basisargument 0 ist, hängt die Konvertierung von den ersten beiden Zeichen von str ab:

Wenn das erste Zeichen eine Ziffer von 1 bis 9 ist, wird angenommen, dass die Zahl in 10 c/c dargestellt wird;

Wenn das erste Zeichen die Zahl 0 und das zweite Zeichen eine Zahl von 1 bis 7 ist, wird angenommen, dass die Zahl in 8 c/c dargestellt wird;

Wenn das erste Zeichen 0 und das zweite Zeichen 'X' oder 'x' ist, wird angenommen, dass die Zahl in 16 c/c dargestellt wird.

Wenn das Basisargument eine Zahl von 2 bis 36 ist, wird dieser Wert als Basis des Zahlensystems genommen, und jedes Zeichen, das über dieses System hinausgeht, stoppt die Konvertierung. Zahlensysteme mit der Basis 11 bis 36 verwenden die Symbole „A“ bis „Z“ oder „a“ bis „z“, um Ziffern darzustellen.

Der Wert des endptr-Arguments wird von der strtol-Funktion festgelegt. Dieser Wert enthält einen Zeiger auf das Zeichen, das die Konvertierung von str gestoppt hat. Die Funktion strtol gibt bei Erfolg die konvertierte Zahl zurück und bei einem Fehler 0. Beispiel:

n = strtol("12a", &p, 0);

printf(" n = %ld, %stop = %c, n, *p); // n = 12, Stopp = a

n = strtol("012b", &p, 0);

printf(" n = %ld, %stop = %c, n, *p); // n = 10, Stopp = b

n = strtol("0x12z", &p, 0);

printf(" n = %ld, %stop = %c, n, *p); // n = 18, Stopp = z

n = strtol("01117", &p, 0);

printf(" n = %ld, %stop = %c, n, *p); // n = 7, Stopp = 7

unsigned long int strtol (const char *str, char **endptr, int base);

funktioniert ähnlich wie die strtol-Funktion, wandelt aber die Zeichendarstellung einer Zahl in ein unsigned long int um.

double strtod (const char *str, char **endptr);

wandelt die symbolische Darstellung einer Zahl in ein Double um.

Alle in diesem Absatz aufgeführten Funktionen beenden ihre Arbeit, wenn sie auf das erste Zeichen stoßen, das nicht in das Format der betreffenden Nummer passt.

Wenn außerdem der Zeichenwert einer Zahl den zulässigen Wertebereich für den entsprechenden Datentyp überschreitet, setzen die Funktionen atof, strtol, strtoul, strtod den Wert der Variablen errno auf ERANGE. Die Variable errno und die Konstante ERANGE sind in der Header-Datei math.h definiert. Die Funktionen atof und strtod geben HUGE_VAL zurück, die Funktion strtol gibt LONG_MAX oder LONG_MIN zurück und die Funktion strtoul gibt ULONG_MAX zurück.

Die nicht standardmäßigen Funktionen itoa, ltoa, utoa, ecvt, fcvt und gcvt können verwendet werden, um numerische Daten in Zeichenfolgen umzuwandeln. Aber es ist besser, die Standardfunktion sprintf für diese Zwecke zu verwenden.

1.6. Standardfunktionen für die Arbeit mit Strings.

In diesem Abschnitt werden Funktionen zum Arbeiten mit Strings betrachtet, deren Prototypen in der Header-Datei string.h beschrieben sind.

1. Zeichenfolgenvergleich. Die Funktionen strcmp und strncmp werden zum Vergleichen von Zeichenfolgen verwendet.

int strcmp (const char *str1, const char *str2);

vergleicht die Zeichenfolgen str1, str2 lexikografisch und gibt -1, 0 oder 1 zurück, wenn str1 kleiner, gleich oder größer als str2 ist.

int strncmp (const char *str1, const char *str2, size_t n);

vergleicht lexikografisch höchstens die ersten n Zeichen der Zeichenketten str1 und str2. Die Funktion gibt -1, 0 oder 1 zurück, wenn die ersten n Zeichen von str1 kleiner, gleich oder größer als die ersten n Zeichen von str2 sind.

// Beispiel für String-Vergleich

#enthalten

#enthalten

char str1 = "aa bb";

char str2 = "aa aa";

char str3 = "aa bb cc";

printf("%d\n", strcmp(str1, str3)); // gibt aus: -1

printf("%d\n", strcmp(str1, str1)); // gibt aus: -0

printf("%d\n", strcmp(str1, str2)); // druckt: 1

printf("%d\n", strncmp(str1, str3, 5)); // gibt aus: 0

2. Zeilen kopieren. Die Funktionen strcpy und strncpy werden zum Kopieren von Zeichenfolgen verwendet.

char *strcpy (char *str1, const char *str2);

kopiert den String str2 in den String str1. Die Zeichenfolge str2 wird vollständig kopiert, einschließlich des abschließenden Nullbytes. Die Funktion gibt einen Zeiger auf str1 zurück. Wenn sich die Linien überlappen, ist das Ergebnis unvorhersehbar.

char *strncpy (char *str1, const char *str2, size_t n);

kopiert n Zeichen von String str2 nach String str1. Wenn die Zeichenfolge str2 weniger als n Zeichen enthält, wird das letzte Nullbyte so oft wie nötig kopiert, um die Zeichenfolge str2 auf n Zeichen zu erweitern. Die Funktion gibt einen Zeiger auf den String str1 zurück.

char str2 = "Zeichenfolge kopieren.";

strcpy(str1, str2);

printf(str1); // druckt: Zeichenfolge kopieren.

4. Verbindungsschnüre. Die Funktionen strcat und strncat werden verwendet, um Strings zu einem einzigen String zu verketten.

char* strcat (char *str1, const char *str2);

hängt die Zeichenfolge str2 an die Zeichenfolge str1 an, wobei das abschließende Null-Byte der Zeichenfolge str1 gelöscht wird. Die Funktion gibt einen Zeiger auf den String str1 zurück.

char* strncat (char *str1, const char *str2, size_t n);

verkettet n Zeichen von String str2 zu String str1 und löscht das abschließende Null-Byte von str1. Die Funktion gibt einen Zeiger auf den String str1 zurück. wenn die Länge des Strings str2 kleiner als n ist, dann werden nur die im String str2 enthaltenen Zeichen angehängt. Nach der Zeichenfolgenverkettung wird str1 immer ein Nullbyte hinzugefügt. Die Funktion gibt einen Zeiger auf den String str1 zurück.

#enthalten

#enthalten

char str1 = "Zeichenfolge";

char str2 = "Verkettung";

char str3 = "Ja Nein";

strcat(str1, str2);

printf("%s\n", str1); // gibt aus: Zeichenfolgenverkettung

strncat(str1, str3, 3);

printf("%s\n", str1); // gibt aus: Zeichenfolgenverkettung Ja

5. Suchen Sie nach einem Zeichen in einer Zeichenfolge. Die Funktionen strchr, strrchr, strspn, strcspn und strpbrk werden verwendet, um nach einem Zeichen in einer Zeichenfolge zu suchen.

char* strchr (const char *str, int c);

sucht nach dem ersten Vorkommen des durch den Parameter c angegebenen Zeichens in der Zeichenkette str. Bei Erfolg gibt die Funktion einen Zeiger auf das erste gefundene Zeichen zurück und bei Misserfolg NULL.

char* strrchr (const char *str, int c);

sucht nach dem letzten Vorkommen des durch den Parameter c angegebenen Zeichens in der Zeichenkette str. Bei Erfolg gibt die Funktion einen Zeiger auf das letzte gefundene Zeichen zurück und bei Misserfolg NULL.

#enthalten

#enthalten

char str = "Zeichensuche";

printf("%s\n", strchr(str, "r")); // gibt aus: r-Suche

printf("%s\n", strrchr(str, "r")); // druckt: rch

size_t strspn (const char *str1, const char *str2);

gibt den Index des ersten Zeichens in str1 zurück, das nicht in str2 ist.

size_t strcspn (const char *str1, const char *str2);

gibt den Index des ersten Zeichens in str1 zurück, das sich in str2 befindet.

char str = "123 abc";

printf("n = %d\n", strspn(str, "321"); // gibt aus: n = 3

printf ("n = %d\n", strcspn (str, "cba"); // gibt aus: n = 4

char* strpbrk (const char *str1, const char *str2);

findet das erste Zeichen in str1, das einem der Zeichen in str2 entspricht. Bei Erfolg gibt die Funktion einen Zeiger auf dieses Zeichen zurück und bei Misserfolg NULL.

char str = "123 abc";

printf("%s\n", strpbrk(str, "bca")); // druckt: abc

6. Vergleich von Saiten. Die strstr-Funktion wird verwendet, um Zeichenfolgen zu vergleichen.

char* strstr (const char *str1, const char *str2);

findet das erste Vorkommen der Zeichenfolge str2 (ohne das abschließende Nullbyte) in der Zeichenfolge str1. Bei Erfolg gibt die Funktion einen Zeiger auf die gefundene Teilzeichenfolge zurück und bei Misserfolg NULL. Wenn der str1-Zeiger auf eine Zeichenfolge der Länge Null zeigt, gibt die Funktion den str1-Zeiger zurück.

char str = "123 abc 456;

printf("%s\n", strstr(str, "abc"); // drucke: abc 456

7. Parsing einer Zeichenkette in Tokens. Die strtok-Funktion wird verwendet, um eine Zeichenfolge in Token zu zerlegen.

char* strtok (char *str1, const char *str2);

gibt einen Zeiger auf das nächste Token (Wort) in Zeichenfolge str1 zurück, wobei Token-Trennzeichen Zeichen aus Zeichenfolge str2 sind. Wenn die Token vorbei sind, gibt die Funktion NULL zurück. Beim ersten Aufruf der strtok-Funktion muss der str1-Parameter auf eine Zeichenfolge zeigen, die in Tokens analysiert wird, und bei nachfolgenden Aufrufen muss dieser Parameter auf NULL gesetzt werden. Nachdem das Token gefunden wurde, schreibt die strtok-Funktion ein Null-Byte nach diesem Token anstelle des Trennzeichens.

#enthalten

#enthalten

char str = "12 34 ab cd";

p = strtok(str, " ");

printf("%s\n",p); // gibt Werte in einer Spalte aus: 12 34 ab cd

p = strtok(NULL, " ");

8. Bestimmen der Länge des Strings. Die strlen-Funktion wird verwendet, um die Länge eines Strings zu bestimmen.

size_t strlen(const char *str);

gibt die Länge des Strings zurück, wobei das letzte Nullbyte ignoriert wird. Zum Beispiel,

Zeichenstr = "123";

printf("len = %d\n",strlen(str)); // druckt: len = 3

1.7. Funktionen für die Arbeit mit dem Gedächtnis.

Die Header-Datei string.h beschreibt auch Funktionen zum Arbeiten mit Speicherblöcken, die den entsprechenden Funktionen zum Arbeiten mit Strings ähnlich sind.

void* memchr(const void *str, int c, size_t n);

sucht nach dem ersten Vorkommen des durch c angegebenen Zeichens in n Bytes von str.

int memcmp (const void *str1, const void *str2, size_t n);

vergleicht die ersten n Bytes von str1 und str2.

void* memcpy(const void *str1, const void *str2, size_t n);

kopiert die ersten n Bytes von String str1 nach String str2.

void* memmove(const void *str1, const void *str2, size_t n);

kopiert die ersten n Bytes von str1 nach str2, um sicherzustellen, dass überlappende Zeichenfolgen korrekt behandelt werden.

void* memset(const void *str, int c, size_t n);

kopiert das durch c angegebene Zeichen in die ersten n Bytes von str.

Bitte pausieren Sie AdBlock auf dieser Seite.

Also Strings in C-Sprache. Sie haben keinen separaten Datentyp, wie es in vielen anderen Programmiersprachen der Fall ist. In der C-Sprache ist ein String ein Array von Zeichen. Um das Ende einer Zeile zu markieren, wird das Zeichen „\0“ verwendet, über das wir im letzten Teil dieser Lektion gesprochen haben. Es wird in keiner Weise auf dem Bildschirm angezeigt, daher funktioniert es nicht, es anzusehen.

Erstellen und Initialisieren einer Zeichenfolge

Da ein String ein Array von Zeichen ist, ähnelt das Deklarieren und Initialisieren eines Strings ähnlichen Operationen mit eindimensionalen Arrays.

Der folgende Code veranschaulicht verschiedene Möglichkeiten zum Initialisieren von Zeichenfolgen.

Auflistung 1.

Charstr; char str1 = ("Y","o","n","g","C","o","d","e","r","\0"); char str2 = "Hallo!"; char str3 = "Hallo!";

Abb.1 Deklaration und Initialisierung von Strings

In der ersten Zeile deklarieren wir einfach ein Array aus zehn Zeichen. Es ist nicht einmal wirklich ein String, weil es fehlt das Nullzeichen \0 , solange es sich nur um eine Reihe von Zeichen handelt.

Zweite Reihe. Der einfachste Weg Initialisierung in der Stirn. Wir deklarieren jedes Symbol separat. Das Wichtigste dabei ist, das Nullzeichen \0 nicht zu vergessen.

Die dritte Zeile ähnelt der zweiten Zeile. Achten Sie auf das Bild. Denn Wenn der String rechts weniger Zeichen enthält als Elemente im Array, werden die restlichen Elemente mit \0 gefüllt.

Vierte Zeile. Wie Sie sehen können, wird die Größe hier nicht festgelegt. Das Programm berechnet es automatisch und erstellt ein Array von Zeichen der erforderlichen Länge. Dadurch wird das Nullzeichen \0 zuletzt eingefügt.

So geben Sie einen String aus

Lassen Sie uns den obigen Code zu einem vollwertigen Programm hinzufügen, das die generierten Zeichenfolgen auf dem Bildschirm anzeigt.

Auflistung 2.

#enthalten int main(void) ( char str; char str1 = ("Y","o","n","g","C","o","d","e","r"," \0"); char str2 = "Hallo!"; char str3 = "Hallo!"; for(int i = 0; i< 10; i = i + 1) printf("%c\t",str[i]); printf("\n"); puts(str1); printf("%s\n",str2); puts(str3); return 0; }


Abb. 2 Verschiedene Möglichkeiten, eine Zeichenfolge auf dem Bildschirm anzuzeigen

Wie Sie sehen können, gibt es mehrere grundlegende Möglichkeiten, eine Zeichenfolge auf dem Bildschirm anzuzeigen.

  • Verwenden Sie die printf-Funktion mit dem %s-Spezifizierer
  • Verwenden Sie die Puts-Funktion
  • Verwenden Sie die Funktion fputs und geben Sie stdout als zweiten Parameter an.

Die einzige Einschränkung sind die puts- und fputs-Funktionen. Beachten Sie, dass die Funktion puts die Ausgabe in die nächste Zeile umbricht, die Funktion fputs jedoch nicht.

Wie Sie sehen können, ist die Ausgabe recht einfach.

Zeichenfolgen eingeben

Bei der String-Eingabe sind die Dinge etwas komplizierter als bei der Ausgabe. Der einfachste Weg wäre folgender:

Auflistung 3.

#enthalten int main(void) ( char str; gets(str); puts(str); return 0; )

Die Funktion gets hält das Programm an, liest eine Zeichenfolge, die über die Tastatur eingegeben wurde, und platziert sie in einem Zeichenarray, dessen Name als Parameter an die Funktion übergeben wird.
Die gets-Funktion endet mit dem Zeichen, das der Eingabetaste entspricht und als Nullzeichen in die Zeichenfolge geschrieben wird.
Gefahr bemerkt? Wenn nicht, wird Sie der Compiler freundlicherweise davor warnen. Das liegt daran, dass die gets-Funktion nur beendet wird, wenn der Benutzer die Eingabetaste drückt. Dies ist mit der Tatsache behaftet, dass wir in unserem Fall über das Array hinausgehen können - wenn mehr als 20 Zeichen eingegeben werden.
Übrigens galten frühere Pufferüberlauffehler als die häufigste Art von Sicherheitslücke. Sie werden heute noch gefunden, aber es ist viel schwieriger geworden, sie zum Hacken von Programmen zu verwenden.

Also was haben wir. Wir haben eine Aufgabe: Schreiben Sie einen String in ein Array begrenzter Größe. Das heißt, wir müssen die Anzahl der vom Benutzer eingegebenen Zeichen irgendwie kontrollieren. Und hier kommt die fgets-Funktion zur Rettung:

Auflistung 4.

#enthalten int main(void) ( char str; fgets(str, 10, stdin); puts(str); return 0; )

Die Funktion fgets akzeptiert drei Argumente als Eingabe: eine Variable zum Schreiben der Zeichenfolge, die Größe der zu schreibenden Zeichenfolge und den Namen des Streams, aus dem die Daten zum Schreiben in die Zeichenfolge abgerufen werden sollen, in diesem Fall stdin . Wie Sie bereits aus Lektion 3 wissen, ist stdin der Standard-Eingabestrom, der normalerweise mit der Tastatur verbunden ist. Es ist nicht notwendig, dass die Daten aus dem stdin-Stream kommen, in Zukunft werden wir diese Funktion auch nutzen, um Daten aus Dateien auszulesen.

Wenn wir während der Ausführung dieses Programms einen String eingeben, der länger als 10 Zeichen ist, werden nur noch 9 Zeichen vom Anfang und das Zeilenumbruchzeichen in das Array geschrieben, fgets "kürzt" den String auf die erforderliche Länge.

Beachten Sie, dass die Funktion fgets nicht 10 Zeichen liest, sondern 9 ! Wie wir uns erinnern, ist in Strings das letzte Zeichen für das Nullzeichen reserviert.

Lass es uns überprüfen. Lassen Sie uns das Programm aus der letzten Auflistung ausführen. Und geben Sie die Zeichenfolge 1234567890 ein. Die Zeichenfolge 123456789 wird auf dem Bildschirm angezeigt.


Abb.3 Ein Beispiel für den Betrieb der fgets-Funktion

Die Frage stellt sich. Wo ist das zehnte Zeichen geblieben? Und ich werde antworten. Es ist nirgendwohin gegangen, es ist im Eingangsstrom geblieben. Führen Sie das folgende Programm aus.

Auflistung 5.

#enthalten int main(void) ( char str; fgets(str, 10, stdin); puts(str); int h = 99; printf("do %d\n", h); scanf("%d",&h) ; printf("nach %d\n", h); gebe 0 zurück; )

Hier ist das Ergebnis ihrer Arbeit.


Abb.4 Nicht leerer stdin-Puffer

Lassen Sie mich erklären, was passiert ist. Wir haben die Funktion fgets aufgerufen. Sie öffnete den Eingabestrom und wartete darauf, dass wir die Daten eingaben. Wir haben 1234567890\n über die Tastatur eingegeben (\n steht für Enter ). Dies ging an den Eingabestrom stdin . Die Funktion fgets nahm wie erwartet die ersten 9 Zeichen 123456789 aus dem Eingabestrom, fügte ihnen das Nullzeichen \0 hinzu und schrieb dies in den String str . Es sind noch 0\n im Eingabestrom übrig.

Als nächstes deklarieren wir die Variable h . Wir zeigen seinen Wert auf dem Bildschirm an. Dann rufen wir die Funktion scanf auf. Hier wird erwartet, dass wir etwas eingeben können, aber da 0\n hängt im Eingabestrom, dann nimmt die scanf-Funktion dies als unsere Eingabe und schreibt 0 in die Variable h . Als nächstes zeigen wir es auf dem Bildschirm an.

Dies ist natürlich nicht genau das Verhalten, das wir erwarten. Um dieses Problem zu lösen, muss der Eingabepuffer gelöscht werden, nachdem wir die vom Benutzer eingegebene Zeichenfolge daraus gelesen haben. Verwenden Sie dazu die Spezialfunktion fflush . Es hat nur einen Parameter - den zu löschenden Stream.

Lassen Sie uns das letzte Beispiel reparieren, damit seine Operation vorhersehbar ist.

Auflistung 6.

#enthalten int main(void) ( char str; fgets(str, 10, stdin); fflush(stdin); // Eingabestrom löschen puts(str); int h = 99; printf("do %d\n", h) ; scanf("%d",&h); printf("nach %d\n", h); gib 0 zurück; )

Jetzt funktioniert das Programm wie es soll.


Abb.4 Leeren des stdin-Puffers mit der fflush-Funktion

Zusammenfassend lassen sich zwei Tatsachen festhalten. Zuerst. Es ist derzeit nicht sicher, die Gets-Funktion zu verwenden, daher wird empfohlen, die fgets-Funktion überall zu verwenden.

Zweite. Vergessen Sie nicht, den Eingabepuffer zu löschen, wenn Sie die Funktion fgets verwenden.

Damit ist das Gespräch über die Eingabe von Zeichenfolgen abgeschlossen. Fortfahren.

»Zuverlässige SEO-Agentur Indien kann den Umsatz kleiner Unternehmen steigern

80 % der Nutzer suchen auf Google und anderen Suchmaschinen, bevor sie einen Kauf tätigen, und mehr als 50 % der über Suchmaschinen generierten Anfragen werden konvertiert. Diese beiden Statistiken belegen die Bedeutung der Suchmaschinenoptimierung. Es gibt viele Statistiken und Fakten, die einen klaren Punkt machen: Jedes kleine, mittlere oder große Unternehmen benötigt professionelle SEO-Dienstleistungen. Kleine Unternehmen und Start-ups stehen oft vor Budgetproblemen. Sie können Hilfe jeder vertrauenswürdigen SEO-Agentur aus Indien in Anspruch nehmen, um den besten SEO-Service in ihrem Budget zu erhalten und ihre Einnahmen zu steigern.
Die Suche hat einen großen Einfluss auf das Bewusstsein der Verbraucher. Laut den verschiedenen Statistiken, die von großen Sauf verschiedenen autorisierten Websites wie Search Engine Land, Moz, SEO Journal, Digital Marketers India, Hubspot usw. geteilt werden. SEO erfasst einen Großteil der Leads. Außerdem haben die Leads aus den organischen Suchergebnissen eine höhere Konversionsrate. Diese Statistiken und das Verbraucherverhalten machen deutlicher, dass der beste SEO-Service kein Luxus, sondern eine Notwendigkeit für jedes Unternehmen ist.
Um die Konkurrenz zu umgehen und das Geschäftswachstum zu steigern, muss jede Organisation die Suchmaschinenoptimierungsdienste nutzen. Die großen Marken können genug Geld für den SEO-Expertenservice investieren, der von einem Top-SEO-Unternehmen oder einem SEO-Spezialisten angeboten wird, aber Kleinunternehmer gehen aufgrund des geringeren Budgets häufig Kompromisse bei der Qualität dieses Services ein. Es ist eine harte Tatsache, dass kleine Unternehmen und Start-ups am Ende die Möglichkeiten verlassen, die mit dem professionellen SEO-Service geschaffen werden können, oder einen billigen SEO-Service nutzen, der keine positiven Ergebnisse liefert.
Die Inhaber kleiner Unternehmen und Startups können auch mit begrenztem Budget von professionellen SEO-Dienstleistungen profitieren. Die beste Lösung ist die Suche nach einem vertrauenswürdigen SEO-Unternehmen mit Sitz in Indien. In Indien gibt es viele SEO-Experten, die mit der Agentur für digitales Marketing zusammenarbeiten und branchenweit beste Dienstleistungen anbieten. Sie können Ihnen die erforderlichen SEO-Dienstleistungen in Ihrem Budget anbieten. Die Löhne können mit einer SEO-Agentur Indien ausgehandelt werden, um bessere Dienstleistungen zu niedrigeren Preisen zu erhalten. Fallen Sie jedoch nicht auf einen billigen SEO-Service herein, der weniger kostet und verspricht, mehr zu geben, da Fachwissen auf seine Kosten kommt. Sie müssen das Portfolio sehen oder die richtigen Fragen stellen, bevor Sie ein Unternehmen für Ihr Unternehmen beauftragen.
Die SEO-Experten in Indien kennen sich mit den Best Practices der Suchmaschinenoptimierung aus. Außerdem gibt es in Indien einige SEO-Spezialisten wie Ash Vyas, die sich darauf spezialisiert haben, die beste Strategie zur Suchmaschinenoptimierung für ein Unternehmen mit festgelegtem Budget zu entwickeln. Die SEO-Profis erstellen einen klaren Plan und teilen auch mit, was die erwarteten Ergebnisse sein können. Auf diese Weise können Sie sich Ihrer Investition und Rendite bewusst sein. Dies hilft, eine bessere Geschäftsentscheidung zu treffen.
Eine gute Idee ist es, so schnell wie möglich ein vertrauenswürdiges SEO-Unternehmen aus Indien zu finden und zu beauftragen, das die besten SEO-Dienstleistungen anbietet. Sie können auch mit einem kleinen Budget und begrenzten Aktivitäten beginnen, um Ihre Webseiten zu indizieren und Ihre Schlüsselwörter in Suchmaschinen zu verbessern. Warten Sie nicht auf den perfekten Zeitpunkt oder Tag, an dem Sie Tausende von Dollars haben, um in die besten SEO-Dienste zu investieren. Wenn Sie früh anfangen, können Sie schneller Ergebnisse erzielen, wenn Sie mit Ihrem Marketingansatz aggressiv vorgehen können. Ein vertrauenswürdiges SEO-Unternehmen mit Sitz in Indien hilft Ihnen dabei, Ihre aktuellen und zukünftigen Pläne zu definieren, um gute Ergebnisse zu erzielen. Mehr indizierte Seiten, verbesserte Rankings und eine glaubwürdige Marke Ihres Unternehmens, die mit kontinuierlichen professionellen SEO-Praktiken erstellt werden, werden Anfragen, Geschäfte und Einnahmen verdoppeln. Jedes kleine Unternehmen kann mit einer zweistelligen Investition in die professionellen SEO-Dienste starten. Es gibt viele SEO-Agenturen in Indien, die ein niedriges Budget anbieten und dennoch aus orientierten Sresultieren.

Umfragen aus dem Exil

  • CraigWew

    12.04.2018

    »Die Bedeutung des Aufbaus einer Beziehung zum Kunden im Immobilien- und allgemeinen Verkauf

    Die Bedeutung des Aufbaus einer Beziehung zum Kunden.
    Der Aufbau einer Beziehung zu einem Kunden muss verdient werden und muss als sehr integraler Bestandteil des Verkaufsprozesses angegangen werden.
    Um einen Kunden und sich selbst dazu zu bringen, eine echte Eins-zu-eins-Beziehung herzustellen, sind zwei Dinge erforderlich!
    Zuerst müssen Sie sich bewusst sein und da sein! Zweitens müssen Sie verstehen, dass es zwei verschiedene Phasen gibt, die während dieses Prozesses auftreten.
    A-Sei da-was bedeutet das?
    o Die meisten Menschen hören einer anderen Person nicht wirklich zu, während sie spricht. Im Allgemeinen sind sie so damit beschäftigt, ihre nächste Antwort oder Aussage zu formulieren, dass sie unmöglich wirklich zuhören können.
    o Wenn das nach Ihnen klingt, bedeutet dabei zu sein, halten Sie die Klappe und hören Sie zu!
    B-Was ist die erste oder Anfangsphase?
    o Im Allgemeinen haben Sie nur wenige Minuten Zeit, um sich in den Köpfen der Kunden als jemand zu etablieren, mit dem sie Geschäfte machen möchten.
    o Im Zweifelsfall ist es am besten, zuerst Fragen zu stellen, die sie herausfordern und über sich selbst sprechen.
    o Es ist auch immer sicher, als Profi aufzutreten – ich meine nicht stoisch oder trocken, sondern jemand, der weiß, was er tut, redet und so aussieht.
    C-Andere Stadien
    o Im Laufe der Zeit werden Sie durch Gespräche und Fragen, die sie haben werden, entweder Ihre Fähigkeit feststellen oder nicht.
    o Seien Sie sich bewusst, dass sie Sie wahrscheinlich noch eine Weile messen werden. Die gute Nachricht ist, dass sie sich irgendwann entspannen werden, wenn Sie erfolgreich eine Beziehung aufgebaut haben, und Sie sich beide darauf konzentrieren können, das Haus zu finden oder zu verkaufen.
    Was kann mir sonst noch helfen, Rapport aufzubauen?
    o Indem Sie versuchen, verschiedene Persönlichkeitstypen zu verstehen und dann die richtigen Fragen zu stellen und zu sagen.
    o Wenn Sie ein gutes Verhältnis haben (auf die gleiche Wellenlänge wie der Kunde kommen), ist der Verkauf im Grunde beendet, jetzt geht es nur noch darum, das richtige Haus zu finden oder die Inseratspapiere auszufüllen.
    Was ist mit verschiedenen Persönlichkeiten
    o Da dies kein Buch über Psychiatrie ist, verstehen Sie vorerst nur zwei Haupttypen.
    o Es gibt introvertierte und extrovertierte Menschen.
    o Sie kennen den Typ. Denken Sie an drei Personen, die Sie kennen und die zu jeder Klassifizierung passen.
    Was ist mit Körpersprache und Sprachmustern?
    o Wenn sie schnell oder langsam sprechen, versuchen Sie, ihre Sprachmuster nachzuahmen.
    o Wenn sie laut oder leise sprechen, tun Sie dasselbe. Neigen sie sich nach vorne oder nach hinten?
    o Unnötig zu erwähnen, dass zu diesem Thema viele Bücher geschrieben wurden. Seien Sie sich nur bewusst, dass dies ein wichtiger Faktor ist – besonders wenn Sie in einem Konferenzraum oder bei jemandem zu Hause sitzen und einen 400.000-Dollar-Deal besprechen.
    Rapport zu entwickeln ist eine Fähigkeit, die erlernt und verbessert werden kann.
    o Wir alle haben schon einmal einen Verkäufer erlebt, der uns etwas verkauft hat, und trotzdem hatten wir nicht das Gefühl, verkauft zu werden. Der Grund dafür ist, dass er oder sie dafür gesorgt hat, dass Sie sich dort wohlfühlen, wo Sie ihm vertraut haben.
    Wie entwickeln wir Rapport?
    o Verwenden Sie Ihre Augen und Ohren und stellen Sie Fragen. erklären
    o Verwenden Sie die Augen:
    o Schauen Sie sich ihre Kleidung an – ihr Auto – ihre persönlichen Besitztümer, und ich meine wirklich, schauen Sie sie an und entziffern Sie, was Ihnen das über sie sagt.
    o Verwenden Sie die Ohren:
    o Hören Sie zu, was sie sagen, und stellen Sie Fragen, um ihrer wahren MOTIVATION auf den Grund zu gehen!
    Während all dieser Gespräche werden Sie wahrscheinlich ein oder zwei Dinge entdecken, die Sie mit ihnen gemeinsam haben. (Familie, geografische Gebiete, Angeln usw.) Wenn Sie auf Gemeinsamkeiten stoßen, lassen Sie sie wissen, dass Sie vertraut sind, und nehmen Sie sich dann eine Minute Zeit, um mit ihnen darüber zu sprechen.
    Was ist das Ziel?
    o Sobald sie Sie als einen von ihnen akzeptieren, können Sie wirklich eine großartige Erfahrung im Verkauf machen, da Sie jetzt als Team zusammenarbeiten – Sie sind nicht mehr der Verkäufer, den Sie jetzt in einer beratenden Position haben .
    o Denken Sie daran, dass der Kunde Sie entweder in seine Welt eintreten lässt oder nicht. Wenn du das verstehst und wirklich hart daran arbeitest, einfühlsam mit ihm/ihr zu werden, kannst du eine Position des Vertrauens erlangen. In den meisten Fällen werden Sie tatsächlich sehen, wie sie sich entspannen (Körpersprache), wenn dies passiert, wenn Sie unterwegs sind.
    o Um dies zu veranschaulichen, haben Sie schon einmal eine Rede gehalten und festgestellt, dass ein Zuhörer, wenn Sie ihn schließlich erreichen, zustimmend nickt. Diese Dinge mögen alle banal erscheinen, sind es aber nicht.
    Wenn Sie das Vertrauen eines Kunden gewinnen können, ist der Verkauf eines Produkts oder einer Dienstleistung viel einfacher und die Erfahrung kann für alle Beteiligten angenehm sein.
    Denken Sie immer daran, dass ein Win/Win die beste Situation ist.

Habra, hallo!

Vor nicht allzu langer Zeit hatte ich einen ziemlich interessanten Vorfall, in den einer der Lehrer einer Hochschule für Informatik verwickelt war.

Das Gespräch über das Programmieren unter Linux drehte sich langsam dahin, dass diese Person anfing zu argumentieren, dass die Komplexität der Systemprogrammierung eigentlich stark übertrieben wird. Dass die C-Sprache so einfach wie ein Streichholz ist, genau wie der Linux-Kernel (in seinen Worten).

Ich hatte einen Linux-Laptop dabei, der über einen Gentleman-Satz von C-Entwicklungstools (gcc, vim, make, valgrind, gdb) verfügte. Ich weiß nicht mehr, welches Ziel wir uns damals gesetzt hatten, aber nach ein paar Minuten stand mein Gegner hinter diesem Laptop, bereit, das Problem zu lösen.

Und buchstäblich in den allerersten Zeilen machte er einen schwerwiegenden Fehler, als er Speicher für ... eine Zeile zuordnete.

Char *str = (char *)malloc(sizeof(char) * strlen(buffer));
buffer ist eine Stapelvariable, die mit Daten von der Tastatur gefüllt wurde.

Ich denke, es wird definitiv Leute geben, die fragen werden: „Stimmt hier etwas nicht?“.
Glaube es kann.

Und was genau - lesen Sie auf der Katze.

Ein bisschen Theorie - eine Art LikBez.

Wenn Sie es wissen, scrollen Sie zur nächsten Überschrift.

Ein String in C ist ein Array von Zeichen, das eigentlich immer mit "\0" enden sollte - dem Zeilenendezeichen. Strings auf dem Stapel (statisch) werden wie folgt deklariert:

Zeichenkette[n] = ( 0 );
n ist die Größe des Zeichenarrays, genau wie die Länge der Zeichenfolge.

Zuweisung ( 0 ) - "Nulling" der Zeichenfolge (optional, Sie können ohne sie deklarieren). Das Ergebnis ist dasselbe wie bei den Funktionen memset(str, 0, sizeof(str)) und bzero(str, sizeof(str)). Wird verwendet, um zu verhindern, dass Müll in nicht initialisierte Variablen geworfen wird.

Sie können auch sofort einen String auf dem Stack initialisieren:

Char buf = "Standardpuffertext\n";
Außerdem kann ein String als Pointer deklariert werden und ihm Speicher auf dem Heap zuweisen:

Char *str = malloc(Größe);
size - die Anzahl der Bytes, die wir der Zeichenfolge zuweisen. Solche Strings nennt man dynamisch (weil die benötigte Größe dynamisch berechnet wird + die allokierte Speichergröße jederzeit mit der Funktion realloc() erhöht werden kann).

Bei einer Stack-Variablen habe ich die Notation n verwendet, um die Größe des Arrays zu bestimmen, bei einer Variablen auf dem Heap habe ich die Notation size verwendet. Und dies fängt perfekt den wahren Kern des Unterschieds zwischen einer Deklaration auf dem Stack und einer Deklaration mit Speicherzuweisung auf dem Heap ein, da n normalerweise verwendet wird, wenn es um die Anzahl der Elemente geht. Und Größe ist eine ganz andere Geschichte ...

Valgrind wird uns helfen

Ich habe es auch in meinem vorherigen Artikel erwähnt. Valgrind ( , zwei - kleine Anleitung) - sehr nützliches Programm, was dem Programmierer hilft, Speicherlecks und Kontextfehler aufzuspüren, genau die Dinge, die am häufigsten auftauchen, wenn man mit Strings arbeitet.

Schauen wir uns ein kleines Listing an, das etwas Ähnliches wie das von mir erwähnte Programm implementiert, und führen Sie es durch valgrind:

#enthalten #enthalten #enthalten #define HELLO_STRING "Hallo, Habr!\n" void main() ( char *str = malloc(sizeof(char) * strlen(HELLO_STRING)); strcpy(str, HELLO_STRING); printf("->\t%s" , str); frei(str); )
Und tatsächlich das Ergebnis des Programms:

$ gcc main.c $ ./a.out -> Hallo Habr!
Bisher nichts Außergewöhnliches. Lassen Sie uns nun dieses Programm mit valgrind ausführen!

$ valgrind --tool=memcheck ./a.out ==3892== Memcheck, ein Speicherfehlerdetektor ==3892== Copyright (C) 2002-2015 und GNU GPL"d, von Julian Seward et al. == 3892== Unter Verwendung von Valgrind-3.12.0 und LibVEX; mit -h für Copyright-Informationen erneut ausführen ==3892== Befehl: ./a.out ==3892== ==3892== Ungültiger Schreibvorgang der Größe 2 ==3892= = bei 0x4005B4: main (in /home/indever/prg/C/public/a.out) ==3892== Adresse 0x520004c ist 12 Bytes innerhalb eines Blocks der Größe 13 alloc"d ==3892== bei 0x4C2DB9D: malloc (vg_replace_malloc.c:299) ==3892== von 0x400597: main (in /home/indever/prg/C/public/a.out) ==3892== ==3892== Ungültiger Lesevorgang der Größe 1 == 3892== bei 0x4C30BC4: strlen (vg_replace_strmem.c:454) ==3892== bei 0x4E89AD0: vfprintf (in /usr/lib64/libc-2.24.so) ==3892== bei 0x4E90718: printf (in /usr/ lib64/libc-2.24.so) ==3892== von 0x4005CF: main (in /home/indever/prg/C/public/a.out) ==3892== Adresse 0x520004d ist 0 Bytes nach einem Block der Größe 13 alloc"d ==3892== bei 0x4C2DB9D: malloc (vg_replace_malloc.c:299) ==3892== bei 0x400597: main (in /home/ endever/prg/C/public/a.out) ==3892== -> Hallo Habr! ==3892== ==3892== HEAP-ZUSAMMENFASSUNG: ==3892== beim Beenden verwendet: 0 Bytes in 0 Blöcken ==3892== Heap-Nutzung insgesamt: 2 Zuweisungen, 2 freie, 1.037 Bytes zugewiesen ==3892= ===3892== Alle Heap-Blöcke wurden freigegeben -- keine Lecks sind möglich ==3892== ==3892== Für Zählungen von erkannten und unterdrückten Fehlern erneut ausführen mit: -v ==3892== FEHLERZUSAMMENFASSUNG: 3 Fehler aus 2 Kontexten (unterdrückt: 0 von 0)
==3892== Alle Heap-Blöcke wurden freigegeben - keine Leaks möglich- es gibt keine Lecks, und es gefällt. Aber es lohnt sich, die Augen etwas tiefer zu senken (obwohl ich anmerken möchte, dass dies nur eine Zusammenfassung ist, die Hauptinformationen an einer etwas anderen Stelle stehen):

==3892== FEHLERSUMMARY: 3 Fehler aus 2 Kontexten (unterdrückt: 0 von 0)
3 Fehler. in 2 Kontexten. In so einem einfachen Programm. Wie!?

Ja, ganz einfach. Der ganze "Trick" besteht darin, dass die strlen-Funktion das Zeilenendezeichen "\0" nicht berücksichtigt. Auch wenn es explizit im Eingabestring angegeben ist (#define HELLO_STRING "Hello, Habr!\n\0"), wird es ignoriert.

Direkt über dem Ergebnis der Programmausführung befinden sich die Linien -> Hallo Habr! es gibt einen ausführlichen bericht darüber, was und wo unserem lieben valgrind nicht gefallen hat. Ich schlage vor, dass Sie sich diese Zeilen selbst ansehen und Ihre eigenen Schlussfolgerungen ziehen.

Tatsächlich sieht die richtige Version des Programms so aus:

#enthalten #enthalten #enthalten #define HELLO_STRING "Hallo, Habr!\n" void main() ( char *str = malloc(sizeof(char) * (strlen(HELLO_STRING) + 1)); strcpy(str, HELLO_STRING); printf("->\ t%s", str); kostenlos(str); )
Wir passieren Valgrind:

$ valgrind --tool=memcheck ./a.out -> Hallo Habr! ==3435== ==3435== HEAP-ZUSAMMENFASSUNG: ==3435== beim Beenden verwendet: 0 Bytes in 0 Blöcken ==3435== Heap-Nutzung insgesamt: 2 Zuweisungen, 2 freie, 1.038 Bytes zugewiesen ==3435= ===3435== Alle Heap-Blöcke wurden freigegeben -- keine Lecks sind möglich ==3435== ==3435== Für Zählungen erkannter und unterdrückter Fehler erneut ausführen mit: -v ==3435== FEHLERZUSAMMENFASSUNG: 0 Fehler aus 0 Kontexten (unterdrückt: 0 aus 0)
Bußgeld. Es gibt keine Fehler, +1 Byte zugewiesener Speicher hat geholfen, das Problem zu lösen.

Interessanterweise funktionieren in den meisten Fällen sowohl das erste als auch das zweite Programm auf die gleiche Weise, aber wenn der für die Zeile, die nicht in das Endzeichen passte, zugewiesene Speicher nicht auf Null gesetzt wurde, dann wird die Funktion printf () bei der Anzeige eines solchen eine Zeile, wird auch den gesamten Müll nach dieser Zeile anzeigen - alles wird gedruckt, bis das Zeilenendezeichen printf () im Wege steht.

Wie Sie jedoch wissen, ist (strlen(str) + 1) eine solche Lösung. Wir stehen vor 2 Problemen:

  1. Aber was ist, wenn wir Speicher für einen String zuweisen müssen, der beispielsweise mit s(n)printf(..) gebildet wurde? Wir unterstützen keine Argumente.
  2. Aussehen. Die Zeile mit der Deklaration einer Variablen sieht einfach schrecklich aus. Einige Leute schaffen es auch, (char *) zu malloc hinzuzufügen, als ob sie unter Pluszeichen schreiben würden. In einem Programm, in dem Sie regelmäßig Strings verarbeiten müssen, ist es sinnvoll, eine elegantere Lösung zu finden.
Lassen Sie uns eine Lösung finden, die sowohl uns als auch Valgrind zufriedenstellt.

snprintf()

int snprintf(char *str, size_t size, const char *format, ...);- Funktion - eine Erweiterung von sprintf, die einen String formatiert und in den als erstes Argument übergebenen Zeiger schreibt. Es unterscheidet sich von sprintf() darin, dass nicht mehr Bytes nach str geschrieben werden, als in size angegeben ist.

Die Funktion hat ein interessantes Feature - in jedem Fall gibt sie die Größe des generierten Strings zurück (ohne das Zeilenendezeichen). Wenn die Zeichenfolge leer ist, wird 0 zurückgegeben.

Eines der Probleme mit strlen, das ich beschrieben habe, hängt mit den Funktionen sprintf() und snprintf() zusammen. Angenommen, wir müssen etwas in die Zeichenfolge str schreiben. Der letzte String enthält die Werte anderer Variablen. Unser Eintrag sollte so aussehen:

Char * str = /* Speicher hier zuweisen */; sprintf(str, "Hallo, %s\n", "Habr!");
Es stellt sich die Frage: Wie kann bestimmt werden, wie viel Speicher für die Zeichenfolge str zugewiesen werden soll?

Char * str = malloc(sizeof(char) * (strlen(str, "Hallo, %s\n", "Habr!") + 1)); - es wird nicht funktionieren. Der Prototyp der Funktion strlen() sieht folgendermaßen aus:

#enthalten size_t strlen(const char *s);
const char *s bedeutet nicht, dass der an s übergebene String ein variadischer Formatstring sein kann.

Diese nützliche Eigenschaft der Funktion snprintf(), die ich oben erwähnt habe, wird uns hier helfen. Schauen wir uns den Code für das folgende Programm an:

#enthalten #enthalten #enthalten void main() ( /* Da snprintf() das Zeilenendezeichen nicht berücksichtigt, addiere seine Größe zum Ergebnis */ size_t benötigte_mem = snprintf(NULL, 0, "Hallo, %s!\n", "Habr") + sizeof("\0"); char *str = malloc(needed_mem); snprintf(str, need_mem, "Hallo, %s!\n", "Habr"); printf("->\t %s", str); kostenlos(str); )
Führen Sie das Programm in Valgrind aus:

$ valgrind --tool=memcheck ./a.out -> Hallo Habr! ==4132== ==4132== HEAP-ZUSAMMENFASSUNG: ==4132== beim Beenden verwendet: 0 Bytes in 0 Blöcken ==4132== Heap-Nutzung insgesamt: 2 Zuweisungen, 2 freie, 1.041 Bytes zugewiesen ==4132= ===4132== Alle Heap-Blöcke wurden freigegeben -- keine Lecks sind möglich ==4132== ==4132== Für Zählungen von erkannten und unterdrückten Fehlern erneut ausführen mit: -v ==4132== FEHLERZUSAMMENFASSUNG: 0 Fehler aus 0 Kontexten (unterdrückt: 0 aus 0) $
Bußgeld. Wir haben Unterstützung für Argumente. Da wir Null als zweites Argument an die Funktion snprintf() übergeben, führt das Schreiben mit einem Nullzeiger niemals zu einem Seagfault. Trotzdem gibt die Funktion die für die Zeichenfolge erforderliche Größe zurück.

Aber andererseits mussten wir eine zusätzliche Variable einführen, und zwar die Konstruktion

Size_t benötigte_mem = snprintf(NULL, 0, "Hallo, %s!\n", "Habr") + sizeof("\0");
sieht noch schlimmer aus als bei strlen().

Im Allgemeinen kann + sizeof("\0") entfernt werden, indem explizit "\0" am Ende des Formatstrings angegeben wird (size_t benötigte_mem = snprintf(NULL, 0, "Hello, %s!\n \0 ”, “Habr”);), aber das ist keineswegs immer möglich (je nach String-Verarbeitungsmechanismus können wir ein zusätzliches Byte zuweisen).

Etwas muss getan werden. Ich dachte eine Weile nach und entschied, dass es jetzt an der Zeit ist, an die Weisheit der Alten zu appellieren. Lassen Sie uns eine Makrofunktion beschreiben, die snprintf() mit einem Nullzeiger als erstem Argument und einem Nullzeiger als zweitem Argument aufruft. Und vergessen wir nicht das Ende der Zeile!

#define strsize(args...) snprintf(NULL, 0, args) + sizeof("\0")
Ja, es mag für einige neu sein, aber C-Makros unterstützen eine variable Anzahl von Argumenten, und die Auslassungspunkte teilen dem Präprozessor mit, dass das angegebene Argument der Makrofunktion (in unserem Fall args) mehreren echten Argumenten entspricht.

Lassen Sie uns unsere Lösung in der Praxis überprüfen:

#enthalten #enthalten #enthalten #define strsize(args...) snprintf(NULL, 0, args) + sizeof("\0") void main() ( char *str = malloc(strsize("Hallo, %s\n", "Habr! ")); sprintf(str, "Hallo, %s\n", "Habr!"); printf("->\t%s", str); free(str); )
Mit valgrund ausführen:

$ valgrind --tool=memcheck ./a.out -> Hallo Habr! ==6432== ==6432== HEAP-ZUSAMMENFASSUNG: ==6432== beim Beenden verwendet: 0 Bytes in 0 Blöcken ==6432== Heap-Nutzung insgesamt: 2 Zuweisungen, 2 freie, 1.041 Bytes zugewiesen ==6432= ===6432== Alle Heap-Blöcke wurden freigegeben -- keine Lecks sind möglich ==6432== ==6432== Für Zählungen erkannter und unterdrückter Fehler erneut ausführen mit: -v ==6432== FEHLERZUSAMMENFASSUNG: 0 Fehler aus 0 Kontexten (unterdrückt: 0 aus 0)
Ja, es sind keine Fehler vorhanden. Alles ist richtig. Und Valgrind ist glücklich und der Programmierer kann endlich schlafen gehen.

Aber zum Schluss sage ich noch eines. Falls wir Speicher für eine beliebige Zeichenfolge (auch mit Argumenten) zuweisen müssen, gibt es bereits voll funktionsfähige schlüsselfertige Lösung.

Wir sprechen über die asprintf-Funktion:

#define _GNU_SOURCE /* Siehe feature_test_macros(7) */ #include int asprintf(char **strp, const char *fmt, ...);
Es nimmt einen Zeiger auf einen String (**strp) als erstes Argument und weist dem dereferenzierten Zeiger Speicher zu.

Unser mit asprintf() geschriebenes Programm sieht so aus:

#enthalten #enthalten #enthalten void main() ( char *str; asprintf(&str, "Hallo, %s!\n", "Habr"); printf("->\t%s", str); free(str); )
Und tatsächlich in Valgrind:

$ valgrind --tool=memcheck ./a.out -> Hallo Habr! ==6674== ==6674== HEAP-ZUSAMMENFASSUNG: ==6674== beim Beenden verwendet: 0 Bytes in 0 Blöcken ==6674== Heap-Nutzung insgesamt: 3 Zuweisungen, 3 freie, 1.138 Bytes zugewiesen ==6674= ===6674== Alle Heap-Blöcke wurden freigegeben -- keine Lecks sind möglich ==6674== ==6674== Für Zählungen erkannter und unterdrückter Fehler erneut ausführen mit: -v ==6674== FEHLERZUSAMMENFASSUNG: 0 Fehler aus 0 Kontexten (unterdrückt: 0 aus 0)
Alles ist in Ordnung, aber wie Sie sehen, wurde mehr Speicher zugewiesen, und jetzt gibt es drei Zuweisungen, nicht zwei.Auf schwachen eingebetteten Systemen ist diese Funktion unerwünscht.
Wenn wir außerdem man asprintf in die Konsole schreiben, sehen wir:

KONFORM ZU Diese Funktionen sind GNU-Erweiterungen, nicht in C oder POSIX. Sie sind auch unter *BSD verfügbar. Die FreeBSD-Implementierung setzt strp im Fehlerfall auf NULL.

Dies macht deutlich, dass diese Funktion nur in den GNU-Quellen verfügbar ist.

Fazit

Abschließend möchte ich sagen, dass die Arbeit mit Strings in C ein sehr komplexes Thema ist, das eine Reihe von Nuancen aufweist. Zum Beispiel, um "sicheren" Code zu schreiben, wenn dynamische Auswahl Speicher, wird dennoch empfohlen, statt malloc() die Funktion calloc() zu verwenden - calloc füllt den allokierten Speicher mit Nullen. Nun, oder nachdem Sie Speicher zugewiesen haben, verwenden Sie die Funktion memset (). Andernfalls kann der Müll, der ursprünglich auf dem zugewiesenen Speicherbereich lag, Probleme beim Debuggen und manchmal sogar beim Arbeiten mit dem String verursachen.

Mehr als die Hälfte der mir bekannten C-Programmierer (meistens Anfänger), die auf meine Bitte hin das Problem der Speicherzuweisung für Strings gelöst haben, haben es so gemacht, dass es schließlich zu Kontextfehlern geführt hat. In einem Fall - sogar zu einem Speicherleck (nun, eine Person hat vergessen, kostenlos (str) zu tun, die nicht passiert). Tatsächlich hat mich das dazu inspiriert, diese Kreation zu schaffen, die Sie gerade gelesen haben.

Ich hoffe, dass dieser Artikel für jemanden nützlich sein wird. Warum habe ich das alles eingezäunt - keine Sprache ist einfach. Überall hat seine Feinheiten. Und je mehr Feinheiten der Sprache Sie kennen, desto besser ist Ihr Code.

Ich glaube, dass Ihr Code nach dem Lesen dieses Artikels ein wenig besser wird :)
Viel Glück Habr!

String-Deklarationen

Ein String in der Sprache C ist ein eindimensionales Array von Zeichen, dessen letztes Element das Zeilenendezeichen ist – Null (ein nullterminierter String, dh ein NULL-terminierter String).

Es gibt drei Möglichkeiten, eine Variable vom Typ String in C zu deklarieren, von denen zwei den String zum Zeitpunkt der Deklaration initialisieren.

Erster Weg:

Zeichen-Array-Deklarationen (vergessen Sie nicht, Leerzeichen für die abschließende Null hinzuzufügen):

Zeichen;

Zweiter Weg:

Weisen Sie einer String-Variablen einen Anfangswert zu (in diesem Fall kann der Compiler die Länge des Strings selbst berechnen):

Char s = "Beispiel für String-Initialisierung";

Rechts vom Zuweisungszeichen befindet sich eine String-Konstante. Am Ende der Zeichenfolge wird automatisch eine Null ('\0') hinzugefügt. Zeichenkettenkonstanten werden in einer statischen Speicherklasse abgelegt.

Dritter Weg:

Ein impliziter Hinweis darauf, dass ein Array verwendet wird. Auf der linken Seite des Zuordnungszeichens wird ein Zeiger auf das Symbol angezeigt:

Char *s="Zweite Initialisierungsoption";

Die Variable s ist ein Zeiger auf die Stelle im RAM, an der sich die String-Konstante befindet. Diese Form der Notation hat einen potentiellen Fehler darin, dass ein Zeiger auf ein Zeichen oft als Zeichenkette bezeichnet wird. Der folgende Eintrag ist nur ein Zeiger auf ein Zeichen, da kein Platz für die Zeichenfolge vorhanden ist:

Char*s;

Eingabe einer Zeichenfolge über das Standard-Eingabegerät (Tastatur)

Es gibt eine Reihe von Funktionen zum Arbeiten mit Strings. Für die Eingabe vom Standard-Eingabegerät (Tastatur) werden am häufigsten Bibliotheksfunktionen aus dem Standard-Eingabe- / Ausgabemodul verwendet: Scanf und bekommt.

Um eine Zeichenkette mit der Funktion einzugeben Scanf, verwendet das Format « %S» , und beachten Sie, dass das Adresszeichen nicht vor der Zeilenkennung verwendet wird « & » , da ein eindimensionales Array bereits durch einen Zeiger auf seinen Anfang repräsentiert wird:

scanf("%s", s);

Funktion bekommt () liest Zeichen, bis es ein Zeilenumbruchzeichen erreicht. Die Funktion akzeptiert alle Zeichen bis einschließlich des Zeilenumbruchzeichens. Am Ende der Zeichenfolge wird eine abschließende Null ('\0') hinzugefügt. Funktion bekommt () fügt eine von der Tastatur gelesene Zeichenfolge in einen String-Parameter ein und gibt einen Zeiger auf diesen String zurück (wenn die Operation erfolgreich war) oder NULL (im Falle eines Fehlers). Im folgenden Beispiel werden nach erfolgreichem Abschluss des Vorgangs zwei identische Zeilen auf dem Bildschirm angezeigt:

#enthalten int main() ( char s; char *p; p=gets(s); printf(" \n String %s eingegeben. ",s); if (p) printf(" \n String %s eingegeben. ", p); gib 0 zurück; )

Am Rande sei angemerkt, dass die gets-Funktion oft verwendet wird, um beliebige Daten von der Tastatur als String einzugeben, zwecks weiterer Konvertierung durch die sscanf-Funktion in das gewünschte Format oder zur vorläufigen Analyse der Eingabedaten, zum Beispiel:

#enthalten #enthalten #enthalten int main() ( char s; int x, err; do ( printf(" \n Geben Sie eine Ganzzahl ein -> "); gets(s); err=sscanf(s, "%d",&x); if (err !=1) printf(" \n Eingabefehler. "); ) while (err!=1); printf("\n Integer eingegeben -> %d", x); return 0; )

Zeichenketten auf Standardausgabe (Bildschirm) drucken

Um Strings auf der Standardausgabe (Bildschirm) auszugeben, können Sie zwei Funktionen verwenden Druckf und setzt. In der printf-Funktion wird als Format "%s" übergeben. Der Komfort bei der Verwendung dieser Funktion liegt darin, dass Sie zusätzlich zur Zeichenfolge sofort Daten anderer Typen anzeigen können. Feature-Funktion setzt ist, dass nach Ausgabe der Zeile automatisch zur nächsten Zeile übergegangen wird.

String-Funktionen

Um Strings in die C-Sprache zu konvertieren, wird die String-Bibliothek bereitgestellt. Jede der Funktionen hat ein eigenes Aufzeichnungsformat (Prototyp).

Die am häufigsten verwendeten Funktionen werden in diesem Artikel besprochen. - lesen

Ein Beispiel für Programme (Listing), die mit Strings arbeiten

Fortsetzung des Themas:
Smartphone

Manchmal können Computerbenutzer auf unangenehme Situationen stoßen, wenn etwas aus ihnen unbekannten Gründen nicht funktioniert. Eine häufige Situation, wenn es scheint, dass es ein Internet gibt, ...