DZWON

Są tacy, którzy czytają tę wiadomość przed tobą.
Zapisz się, aby otrzymywać najnowsze artykuły.
E-mail
Imię
Nazwisko
Jak chcesz przeczytać The Bell
Bez spamu
Ciąg to sekwencja znaków ASCII lub UNICODE. Ciągi C.tak jak w większości wysokopoziomowych języków programowania uważane są za odrębny typ wchodzący w skład systemu podstawowych typów języka. Ponieważ język C z założenia jest językiem programowania systemu, nie ma w nim danych typu string, a zwykłe tablice znaków są używane jako ciągi znaków w C.
Historycznie rzecz biorąc, istniały dwie reprezentacje formatu ciągu:
1. format ANSI;
2. Ciągi zakończone znakiem null (używane w SI).

Format ANSI określa, że \u200b\u200bpierwsza pozycja w ciągu to jego długość, po której następują znaki w ciągu. Na przykład reprezentacja ciągu „Mój ciąg!” będzie wyglądać następująco:
11 „M” ”o” „I” ”„ s ”„ t ”” „p” „o” „do” „a” „!”
W ciągach zakończonych wartością null znaczące znaki w ciągu są określane na pierwszej pozycji, a terminatorem ciągu jest zero. Reprezentacja rozważanego wcześniej ciągu w tym formacie to:
„M” „o” „I” ”” ”„ ”„ t ”” „p” „o” „do” ”a” „!” 0

Deklarowanie ciągów w SI


Łańcuchy są implementowane przy użyciu tablic znaków. Dlatego deklaracja ciągu ASCII ma następującą składnię:
nazwa postaci [długość]; Ogłoszenie struny w si ma taką samą składnię, jak deklaracja tablicy znaków jednowymiarowych. Długość łańcucha musi być liczbą całkowitą (w standardzie C89 jest to stała, w standardzie C99 może to być wyrażenie). Długość łańcucha jest określana z uwzględnieniem jednego znaku do przechowywania kończącego zera, więc maksymalna liczba znaczących znaków w ciągu jest o jeden mniejsza niż jego długość. Na przykład ciąg może zawierać maksymalnie dwadzieścia znaków, jeśli jest zadeklarowany w następujący sposób:
char str; Inicjalizacja łańcucha w C jest wykonywana, gdy jest zadeklarowany przy użyciu następującej składni:
char str [długość] \u003d literał ciągu; Literał łańcuchowy to ciąg znaków ASCII ujęty w podwójne cudzysłowy. Przykłady deklarowania ciągów podczas inicjalizacji:
char str1 \u003d "Wprowadź wartość:", słowo2 \u003d ""; Przykład:
const char message \u003d "Komunikat o błędzie!";

Praca ze stringami w SI


Ponieważ łańcuchy C są tablicami znaków, możesz odwołać się do dowolnego znaku w ciągu przez jego indeks. W tym celu używana jest składnia dostępu do elementu tablicy, więc pierwszy znak w ciągu ma indeks równy zero. Na przykład w następującym fragmencie kodu w linii str wszystkie znaki „a” są zastępowane znakami „A” i odwrotnie.
for (int i \u003d 0; str [i]! \u003d 0; i ++)
  {
if (str [i] \u003d\u003d „a”) str [i] \u003d „A”;
else if (str [i] \u003d\u003d „A”) str [i] \u003d „a”;
  }

Tablice ciągów C.


Deklarowanie tablic łańcuchów w języku C jest również możliwe. W tym celu używane są dwuwymiarowe tablice znaków, które mają następującą składnię:
nazwa postaci [kwota] [długość]; Pierwszy rozmiar macierzy wskazuje liczbę wierszy w tablicy, a drugi - maksymalną (biorąc pod uwagę kończące zero) długość każdego wiersza. Na przykład deklaracja tablicy pięciu ciągów o maksymalnej długości 30 znaków znaczących wyglądałaby tak:
char strs; Podczas deklarowania tablic ciągów można przeprowadzić inicjalizację:
nazwa znaku [kwota] [długość] \u003d
(literał ciągu # 1, ... literał ciągu #N);
Liczba literałów ciągów musi być mniejsza lub równa liczbie ciągów w tablicy. Jeśli liczba literałów ciągów jest mniejsza niż rozmiar tablicy, wszystkie inne elementy są inicjowane jako puste ciągi. Długość każdego literału ciągu musi być dokładnie mniejsza niż wartość długości ciągu (aby zapisać kończącą wartość null).
Na przykład:
char days \u003d (
"Styczeń luty marzec kwiecień maj",
"Czerwiec lipiec sierpień wrzesień październik",
"Listopad grudzień"
  };
Deklarując tablice łańcuchów z inicjalizacją, nie wolno podawać liczby ciągów w nawiasach kwadratowych. W tym przypadku liczba wierszy w tablicy zostanie określona automatycznie na podstawie liczby inicjujących literałów łańcuchowych.
Na przykład tablica siedmiu linii:
char days \u003d (
"Poniedziałek wtorek środa czwartek",
"Piątek sobota NIEDZIELA"
  };

Funkcje do pracy ze stringami w SI


Wszystkie funkcje biblioteczne do pracy ze stringami można podzielić na trzy grupy:
1. wejście i wyjście stringów;
2. konwersja strun;
3. ciągi przetwarzania.

Wejście i wyjście ciągów znaków w SI


Możesz użyć sformatowanych funkcji wejścia i wyjścia (printf i scanf) do wprowadzania i wyprowadzania informacji o łańcuchach. Aby to zrobić, podczas wprowadzania lub wyprowadzania zmiennej łańcuchowej należy określić specyfikator typu% sw ciągu formatu. Na przykład dane wejściowe i wyjściowe zmiennej łańcuchowej wyglądałyby następująco:
char str \u003d "";
printf ("Wprowadź ciąg:");
scanf ("% 30s", str);
printf ("Wprowadziłeś:% s", str);
Wadą funkcji scanf podczas wprowadzania danych typu string jest to, że ogranicznikami tej funkcji są:
1. kanał liniowy,
2. tabulacja;
3. spacja.
Dlatego przy użyciu tej funkcji nie można wprowadzić ciągu zawierającego kilka słów oddzielonych spacjami lub tabulatorami. Np. Jeśli w poprzednim programie użytkownik wpisze ciąg: „Wiadomość z kilkoma słowami”, to na ekranie zostanie wyświetlony tylko „Wiadomość”.
Biblioteka stdio.h zawiera funkcje pobierania i wstawiania wyspecjalizowanych funkcji wejściowych i wyjściowych ciągów.

Funkcja gets służy do wprowadzania ciągów i ma następujący tytuł:
char * gets (char * buffer);

Funkcja puts jest przeznaczona do wyprowadzania ciągów i ma następujący nagłówek:
int puts (const char * string); Najprostszy program: wejście i wyjście łańcucha za pomocą funkcji get i puts będzie wyglądać następująco:
char str \u003d "";
printf ("Wprowadź ciąg:"); gets (str);
printf ("Wprowadziłeś:");
puts (str);
Oprócz funkcji wejścia i wyjścia dla strumieni, biblioteka stdio.h zawiera funkcje dla sformatowanego wejścia i wyjścia do łańcuchów. Sformatowana funkcja wejściowa z ciągu ma następujący nagłówek:
int sscanf (const char * ogranicz bufor, const char * ogranicz ciąg, ...); Sformatowane dane wyjściowe funkcji ciągów mają następujące nagłówki:
int sprintf (char * ogranicz bufor,

int snprintf (char * ogranicz bufor, rozmiar_t maksymalny rozmiar,
const char * ogranicz format, ...);

Konwersja ciągów


W C do konwersji łańcuchów zawierających liczby na wartości liczbowe w bibliotece stdlib.h
zapewniony jest następujący zestaw funkcji:
double atof (const char * string); // konwertowanie łańcucha na podwójny
int atoi (const char * string); // konwertowanie łańcucha znaków na liczbę typu int
long int atol (const char * string); // konwertowanie ciągu znaków na długie int
long long int atoll (const char * string); // konwertuje ciąg znaków na liczbę typu long long int
Prawidłowa reprezentacja liczby rzeczywistej w ciągu tekstowym musi mieć następujący format:
[(+ | -)] [cyfry] [. cyfry] [(e | E) [(+ | -)] cyfry]

Po znakach E, e wskazana jest kolejność numerów. Prawidłowa reprezentacja liczby całkowitej w ciągu tekstowym musi mieć następujący format:
[(+ | -)] cyfry

Oprócz powyższych funkcji biblioteka stdlib.h udostępnia również następujące funkcje do konwersji ciągów znaków na liczby rzeczywiste:
float strtof (const char * ogranicz string, char ** ogranicz endptr);
double strtod (const char * ogranicz string, char ** ogranicz endptr);
long double strtold (const char * ogranicz string, char ** ogranicz endptr);

Istnieją podobne funkcje do konwersji łańcuchów na wartości całkowite:
long int strtol (const char * ogranicz string,

unsigned long strtoul (const char * ogranicz string,
char ** ogranicz endptr, int base);
long long int strtoll (const char * ogranicz string,
char ** ogranicz endptr, int base);
unsigned long long strtoull (const char * ogranicz ciąg, char ** ogranicz endptr, int base);

Funkcje konwersji odwrotnej (wartości liczbowe na łańcuchy) są obecne w bibliotece stdlib.h, ale nie są regulowane przez standard i nie będą uwzględniane. Funkcje sprintf i snprintf są najwygodniejsze do konwersji wartości liczbowych na ciągi.

Przetwarzanie ciągów


Biblioteka string.h zawiera funkcje do różnych działań na łańcuchach.
Funkcja obliczania długości łańcucha:
size_t strlen (const char * string); Przykład:
char str \u003d "1234";
int n \u003d strlen (str); // n \u003d\u003d 4
Funkcje kopiowania ciągów:
char * strcpy (char * ogranicz dst, const char * ogranicz src);
char * strncpy (char * ogranicz dst, const char * ogranicz src, size_t num);
Funkcje porównania ciągów:
int strcmp (const char * string1, const char * string2);
int strncmp (const char * string1, const char * string2, size_t num);
Funkcje porównują łańcuchy alfabetycznie i zwracają:
wartość dodatnia - jeśli ciąg1 jest większy niż ciąg2;
wartość ujemna - jeśli ciąg1 jest mniejszy niż ciąg2;
wartość null - jeśli ciąg1 jest tym samym, co ciąg2;

Funkcje konkatenacji (konkatenacji) ciągów:
char * strcat (char * ogranicz dst, const char * ogranicz src);
char * strncat (char * ogranicz dst, const char * ogranicz src, rozmiar_t num);

Funkcje wyszukiwania dla znaku w ciągu:
char * strchr (const char * string, int c);
char * strrchr (const char * string, int c);

Funkcja wyszukiwania ciągów w ciągu:
char * strstr (const char * str, const char * substr);

Przykład:
char str \u003d "Wyszukaj ciąg";
char * słowo1 \u003d słowostr (słowo, "dla"); // str1 \u003d\u003d "do wyszukiwania"

Funkcja wyszukiwania pierwszego znaku w ciągu z podanego zestawu znaków:
size_t strcspn (const char * str, const char * charset);

Funkcje do znajdowania pierwszego znaku w ciągu, który nie należy do podanego zestawu znaków:
size_t strspn (const char * str, const char * charset);

Funkcje do znajdowania pierwszego znaku w ciągu z podanego zestawu znaków:
char * strpbrk (const char * str, const char * charset);

Funkcja wyszukiwania dla następnego literału w ciągu:
char * strtok (char * ogranicz łańcuch, const char * ogranicz zestaw znaków);

Praca ze sznurkami. Klasa String. Konstruktory klas. Funkcje assign (), append (), insert (), replace (), erase (), find (), rfind (), compare (), c_str (). Przykłady

1. Jaki jest cel klasy string w programach C ++?

Klasa string jest zaprojektowana do pracy z ciągami typu char *, które są zakończonymi znakiem null. Klasa string została wprowadzona jako alternatywa dla pracy z łańcuchami typu char *. Linie kończące się znakiem ‘\0’ zwane również ciągami C. Ponieważ string jest klasą, możesz deklarować obiekty tej klasy.

2. Jakie moduły (biblioteki) należy podłączyć, aby korzystać z możliwości klasy string w MS Visual Studio C ++?

Aby skorzystać z możliwości klasy string w MS Visual Studio (C ++), musisz dołączyć bibliotekę i przestrzeń nazw std.

#zawierać using namespace std;
3. W jaki sposób deklarowana jest zmienna typu string? Przykłady

Deklarowanie zmiennej typu string odbywa się w taki sam sposób jak zwykłej zmiennej. Możliwa jednoczesna deklaracja inicjalizacji.

// string type string s1; // zmienna o nazwie s1 typu string string s2 \u003d "To jest zmienna typu string"; // deklaracja z inicjalizacją // używając zmiennej typu string z operatorem przypisania s1 \u003d s2; // s1 \u003d "To jest zmienna typu string" s2 \u003d "Nowy tekst";
4. Jakie są zalety i wady używania klasy string zamiast typu char *?

Utworzenie nowego typu string było spowodowane niedociągnięciami pracy z ciągami znaków, które zademonstrował typ char *. W porównaniu z typem char *, typ string ma następujące główne zalety:

  • możliwość przetwarzania łańcuchów za pomocą standardowych operatorów C ++ ( = , + , = = , <> itp.). Jak wiecie, przy użyciu typu char * nawet najprostsze operacje na łańcuchach wyglądały na skomplikowane i wymagały napisania nadmiernego kodu programistycznego;
  • zapewnienie większej niezawodności (bezpieczeństwa) kodu programu. Na przykład podczas kopiowania ciągów typ ciągu zapewnia odpowiednie działania, które mogą wystąpić, jeśli ciąg źródłowy jest większy niż ciąg docelowy;
  • dostarczanie łańcucha jako niezależnego typu danych. Deklaracja typu string jako string jest taka sama dla wszystkich zmiennych w programie, co zapewnia spójność danych.

Główną wadą typu string w porównaniu z char * jest wolniejsza prędkość przetwarzania danych. Dzieje się tak, ponieważ typ ciągu jest w rzeczywistości klasą kontenera. A praca z klasą wymaga dodatkowej implementacji kodu programu, co z kolei zajmuje więcej czasu.

5. Jakich operatorów można używać z obiektami łańcuchowymi?

Klasa string jest wygodna, ponieważ umożliwia wygodne manipulowanie napisami przy użyciu standardowych (przeciążonych) operatorów.

Następujące operatory mogą być używane z obiektami klasy string

  • = - zadanie
  • + - konkatenacja (konkatenacja ciągów)
  • += - przypisanie z konkatenacją
  • == - równość
  • != - nierówność
  • < - mniejszy
  • <= - mniejszy lub równy
  • > - więcej
  • >= - więcej lub równo
  • - indeksowanie

Przykład, który demonstruje użycie powyższych operatorów

// typ string, operacje na łańcuchach string s1 \u003d "s-1"; string s2 \u003d "s-2"; string s3; bool b; // operacja "\u003d" (przypisanie ciągów) s3 \u003d s1; // s3 \u003d „s-1” // operacja „+” - konkatenacja ciągów s3 \u003d s3 + s2; // s3 \u003d „s-1s-2” // operacja „+ \u003d” - przypisanie z konkatenacją s3 \u003d „s-3”; s3 + \u003d "abc"; // s3 \u003d „s-3abc” // operacja "\u003d\u003d" - porównanie ciągów b \u003d s2 \u003d\u003d s1; // b \u003d false b \u003d s2 \u003d\u003d "s-2"; // b \u003d prawda // operacja "! \u003d" - porównanie ciągów (nierówne) s1 \u003d "s1"; s2 \u003d "s2"; b \u003d s1! \u003d s2; // b \u003d prawda // operacje ”<" и ">"- porównanie ciągów s1 \u003d "abcd"; s2 \u003d „de”; b \u003d s1\u003e s2; // b \u003d false b \u003d s1< s2; // b = true // operacje ”<=" и ">\u003d "- porównanie ciągów (mniejsze lub równe, większe lub równe) s1 \u003d "abcd"; s2 \u003d "ab"; b \u003d s1\u003e \u003d s2; // b \u003d prawda b \u003d s1<= s2; // b = false b = s2 >\u003d "ab"; // b \u003d prawda // operacja - indeksowanie char c; s1 \u003d "abcd"; c \u003d s1; // c \u003d "c" c \u003d s1; // c \u003d "a"
6. Czy klasa string zawiera konstruktory?

Jak każda klasa, klasa string ma kilka konstruktorów. Najważniejsze z nich to:

Strunowy (); string (const char * str); string (const string & str);

7. Przykłady inicjalizacji za pomocą konstruktorów

Poniżej znajdują się przykłady inicjalizacji zmiennych typu string

String s1 („Cześć!”); string s2 \u003d "Witaj!" ; // inicjalizacja - ciąg konstruktora (const char * str) char * ps \u003d "Witaj"; string s3 (ps); // ciąg inicjalizacyjny s4 (s3); // inicjalizacja - konstruktor string (const string & str) string s5; // inicjalizacja - konstruktor string ()

8. Przypisanie strun. Funkcja Assign (). Przykłady

Aby przypisać jeden ciąg do drugiego, możesz użyć jednej z dwóch metod:

  • użyj operatora przypisania ‘=’ ;
  • użyj funkcji assign () z klasy string.

Funkcja assign () ma kilka przeciążonych implementacji.

Pierwsza opcja to wywołanie funkcji bez parametrów

Ciąg i przypisywanie (nieważne);

W tym przypadku istnieje proste przypisanie jednego ciągu do drugiego.

Druga opcja pozwala na skopiowanie określonej liczby znaków z ciągu:

Ciąg i przypisywanie (ciąg i ciąg const, typ_rozmiaru st, typ_rozmiaru numer);

  • s - obiekt, z którego pobierany jest łańcuch źródłowy;
  • st - indeks (pozycja) w ciągu, od którego ma rozpocząć się kopiowanie num znaków;
  • num - liczba znaków do skopiowania z pozycji st;
  • typ_rozmiaru to porządkowy typ danych.

Trzeci wariant funkcji assign () kopiuje pierwszą liczbę znaków ciągu s do wywołującego:

Ciąg i przypisanie (const char * s, numer_rozmiaru);

  • s - ciąg zakończony znakiem ‘\0’ ;
  • liczba to liczba znaków, które są kopiowane do dzwoniącego. Pierwsza liczba znaków z łańcucha s jest kopiowana.

Poniżej znajduje się przykład z różnymi implementacjami funkcji assign ().

Przykład.

// przypisywanie ciągów, funkcja assign () string s1 \u003d "witryna"; string s2; string s3; char * ps \u003d "witryna"; s3 \u003d s1; // s3 \u003d "witryna" s2. assign (s1); // s2 \u003d "witryna" s2. assign (s1, 0, 4); // s2 \u003d "najlepiej" s2. assign (ps, 8); // s2 \u003d "bestprog"
9. Łączenie ciągów. Funkcja Append (). Przykład

Funkcja append () służy do łączenia łańcuchów. Możesz także użyć tej operacji, aby dodać linie ‘+’ np .:

String s1; string s2; s1 \u003d „abc”; s2 \u003d "def"; s1 \u003d s1 + s2; // s1 \u003d "abcdef"

Jednak funkcja append () jest dobra, jeśli chcesz dołączyć część ciągu.

Funkcja ma następujące opcje implementacji:

String & append (const string & s, size_type start); string & append (const char * s, size_type num);

W pierwszej implementacji funkcja otrzymuje łącze do obiektu typu string s który jest dodawany do dzwoniącego. W drugiej implementacji funkcja otrzymuje wskaźnik do łańcucha const char *, który kończy się znakiem „\\ 0”.

Przykład. Demonstracja funkcji append ().

String s1 \u003d "abcdef"; s2 \u003d „1234567890”; dołącz (s2, 3, 4); // s1 \u003d "abcdef4567" char * ps \u003d "1234567890"; s1 \u003d "abcdef"; s1.append (ps, 3); // s1 \u003d „abcdef123”

10. Wstawianie znaków w linii. Funkcja Insert (). Przykład

Aby wstawić jedną linię w danym miejscu innej linii, musisz użyć funkcji insert (), która ma kilka opcji implementacji.

Pierwsza wersja funkcji pozwala na wstawienie całego ciągu znaków na podanej pozycji początkowej linii wywołującej (wywołującego obiektu):

String & insert (size_type start, const string & s);

Druga wersja funkcji pozwala na wstawienie części (parametrów insStart, num) łańcucha s na podanej pozycji początkowej ciągu wywołującego:

Ciąg i wstaw (początek typu_rozmiaru, ciąg znaków stałych i s, typ_rozmiaru insStart, typ_rozmiaru numer);

W powyższych funkcjach:

  • s - ciąg, który ma zostać wstawiony do wywołującego ciągu;
  • start - pozycja w linii wywołującej, z której należy wstawić ciąg s;
  • insStart - pozycja w ciągu znaków, z której należy wstawić;
  • liczba to liczba znaków w łańcuchach wstawianych z pozycji insStart.
string s1 \u003d "abcdef"; string s2 \u003d "1234567890"; s1.insert (3, s2); // s1 \u003d "abc" + "1234567890" + "def" \u003d "abc1234567890def" s2.insert (2, s1, 1, 3); // s2 \u003d „12bcd34567890”
11. Zamiana znaków w ciągu. Funkcja Replace (). Przykład

Funkcja replace () zastępuje znaki w ciągu wywołującym. Funkcja ma następujące opcje implementacji:

Ciąg i zamień (początek typu_rozmiaru, numer typu_rozmiaru, ciąg i ciąg znaków stałych); string & replace (size_type start, size_type num, const string & s, size_type replStart, size_type replNum);

W pierwszej implementacji ciąg wywołujący jest zastępowany ciągiem s. Możliwe jest ustawienie pozycji (początku) oraz liczby znaków (num) w linii wywołującej, które należy zastąpić ciągiem s.

Druga wersja funkcji replace () różni się od pierwszej tym, że umożliwia zastąpienie wywołującego ciągu tylko jego częścią. W tym przypadku podane są dwa dodatkowe parametry: pozycja replStart i liczba znaków w ciągu znaków, które tworzą podłańcuch zastępujący ciąg wywołujący.

Przykład. Demonstracja funkcji replace ().

String s1 \u003d "abcdef"; string s2 \u003d "1234567890"; s2.replace (2, 4, s1); // s2 \u003d "12abcdef7890" s2 \u003d "1234567890"; s2.replace (3, 2, s1); // s2 \u003d "123abcdef67890" s2 \u003d "1234567890"; s2.replace (5, 1, s1); // s2 \u003d „12345abcdef7890” // zamień znaki, funkcja replace () string s1 \u003d "abcdef"; string s2 \u003d "1234567890"; s2.replace (2, 4, s1); // s2 \u003d "12abcdef7890" s2 \u003d "1234567890"; s2.replace (3, 2, s1); // s2 \u003d "123abcdef67890" s2 \u003d "1234567890"; s2.replace (5, 1, s1); // s2 \u003d "12345abcdef7890" s2 \u003d "1234567890"; s2.replace (5, 1, s1, 2, 3); // s2 \u003d "12345cde7890" s2 \u003d "1234567890"; s2.replace (4, 2, s1, 0, 4); // s2 \u003d „1234abcd7890”

12. Usunięcie określonej liczby znaków z ciągu. Funkcja Erase (). Przykład

Aby usunąć znaki z wywołującego ciągu, użyj funkcji erase ():

String & erase (indeks size_type \u003d 0, size_type num \u003d npos);

  • indeks - indeks (pozycja), od którego chcesz usunąć znaki w linii wywołującej;
  • liczba to liczba znaków do usunięcia.

Przykład.

String s \u003d "01234567890"; s. erase (3, 5); // s \u003d "012890" s \u003d "01234567890"; s.erase (); // s \u003d „”

13. Wyszukaj znak w ciągu. Funkcje Find () i rfind (). Przykłady

W klasie string wyszukanie łańcucha w podłańcuchu może odbywać się na dwa sposoby, różniące się kierunkiem wyszukiwania:

  • patrząc na ciąg od początku do końca za pomocą funkcji find ();
  • patrząc na ciąg od końca do początku za pomocą rfind ().

Prototyp funkcji find () to:

Size_type find (const string & s, size_type start \u003d 0) const;

  • s jest podłańcuchem, którego należy szukać w ciągu, który wywołuje daną funkcję. Funkcja wyszukuje pierwsze wystąpienie ciągu s. Jeśli podciąg s zostanie znaleziony w ciągu, który wywołał daną funkcję, zwracana jest pozycja pierwszego wystąpienia. W przeciwnym razie zwracane jest -1;

Prototypem funkcji rfind () jest:

Size_type rfind (const string & s, size_type start \u003d npos) const;

  • s jest podłańcem, którego należy szukać w wywoływanym ciągu. Wyszukiwanie podciągu w ciągu odbywa się od końca do początku. Jeśli w wywoływanym ciągu zostanie znaleziony podciąg s, funkcja zwraca pozycję pierwszego wystąpienia. W przeciwnym razie funkcja zwraca -1;
  • npos - pozycja ostatniego znaku linii wywołującej;
  • start - pozycja, z której wykonywane jest wyszukiwanie.

Przykład 1. Fragment kodu, który demonstruje wynik działania funkcji find ()

// typ string, funkcja find () string s1 \u003d "01234567890"; string s2 \u003d "345"; string s3 \u003d "abcd"; int pos; pos \u003d s1.find (s2); // pos \u003d 3 pos \u003d s1.find (s2, 1); // pos \u003d 3 pos \u003d s1.find ("jklmn", 0); // pos \u003d -1 pos \u003d s1.find (s3); // pos \u003d -1 pos \u003d s2.find (s1); // pos \u003d -1

Przykład 2. Demonstracja funkcji rfind ().

// typ string, funkcje find () i rfind () string s1 \u003d "01234567890"; string s2 \u003d "345"; string s3 \u003d "abcd"; string s4 \u003d "abcd --- abcd"; int pos; pos \u003d s1.rfind (s2); // pos \u003d 3 pos \u003d s1.rfind (s2, 12); // pos \u003d 3 pos \u003d s1.rfind (s2, 3); // pos \u003d 3 pos \u003d s1.rfind (s2, 2); // pos \u003d -1 pos \u003d s2.rfind (s1); // pos \u003d -1 pos \u003d s1.rfind (s3, 0); // pos \u003d -1 // różnica między funkcjami find () i rfind () pos \u003d s4.rfind (s3); // pos \u003d 7 pos \u003d s4.find (s3); // pos \u003d 0
14. Porównanie części strun. Funkcja Compare (). Przykład

Ponieważ typ łańcucha jest klasą, do porównania dwóch ciągów można użyć operacji ‘= =’ ... Jeśli dwa ciągi są takie same, porównanie będzie prawdziwe. W przeciwnym razie porównanie będzie fałszywe.

Ale jeśli chcesz porównać część jednego ciągu z innym, to służy do tego funkcja compare ().

Prototyp funkcji compare ():

int compare (size_type start, size_type num, const string & s) const;
  • s - ciąg do porównania z ciągiem wywołującym;
  • start - pozycja (indeks) w łańcuchu s, od której ma rozpocząć się przeglądanie znaków ciągu w celu porównania;
  • liczba to liczba znaków w łańcuchach do porównania z wywołującym ciągiem.

Funkcja działa w następujący sposób. Jeśli ciąg wywołujący jest mniejszy niż ciąg s, funkcja zwraca -1 (wartość ujemna). Jeśli wywołujący ciąg jest większy niż ciąg s, funkcja zwraca 1 (wartość dodatnia). Jeśli dwa ciągi są równe, funkcja zwraca 0.

Przykład... Demonstracja funkcji compare ():

// typ ciągu, funkcja porównaj () string s1 \u003d "012345"; string s2 \u003d "0123456789"; int res; res \u003d s1.compare (s2); // res \u003d -1 res \u003d s1.compare ("33333"); // res \u003d -1 res \u003d s1.compare ("012345"); // res \u003d 0 res \u003d s1.compare ("345"); // res \u003d -1 res \u003d s1.compare (0, 5, s2); // res \u003d -1 res \u003d s2.compare (0, 5, s1); // res \u003d -1 res \u003d s1.compare (0, 5, "012345"); // res \u003d -1 res \u003d s2.compare (s1); // res \u003d 1 res \u003d s2.compare ("456"); // res \u003d -1 res \u003d s2.compare ("000000"); // res \u003d 1
15. Pobranie łańcucha ze znakiem końca wiersza „\\ 0” (znak *). Funkcja C_str (). Przykład

Aby uzyskać ciąg kończący się znakiem ‘\0’ używana jest funkcja c_str ().

Prototyp funkcji:

const char * c_str () const;

Funkcja jest zadeklarowana z modyfikatorem const. Oznacza to, że funkcja nie może modyfikować wywołującego (ciągu znaków).

Przykład 1... Konwersja stringa na const char *.

string s \u003d "abcdef"; const char * ps; ps \u003d s.c_str (); // ps \u003d "abcdef"

Przykład 2.

Poniżej przedstawiono konwertowanie ciągu z ciągu na typ System :: String w celu wyświetlenia go w kontrolce Label dla aplikacji aplikacji Windows Forms.

// typ string, funkcja c_str () string s \u003d "abcdef"; String ss; ss \u003d gcnew String (s.c_str ()); // konwertuj label1-\u003e Text \u003d ss; // wyświetl na formularzu

Habra, witaj!

Nie tak dawno miałem dość ciekawy incydent, w który zaangażowany był jeden z nauczycieli na uczelni informatycznej.

Rozmowa o programowaniu w Linuksie powoli doprowadziła do punktu, w którym ten człowiek zaczął argumentować, że złożoność programowania systemów jest w rzeczywistości rażąco przesadzona. Że język C jest tak prosty, jak dopasowanie, w rzeczywistości, jak jądro Linuksa (w jego słowach).

Miałem ze sobą laptopa z Linuksem i zestawem narzędzi programistycznych C dla mężczyzn (gcc, vim, make, valgrind, gdb). Nie pamiętam już, jaki cel sobie wtedy postawiliśmy, ale po kilku minutach mój przeciwnik znalazł się za tym laptopem, całkowicie gotowy do rozwiązania problemu.

I dosłownie w pierwszych liniach popełnił poważny błąd przy przydzielaniu pamięci dla ... linii.

Char * str \u003d (char *) malloc (sizeof (char) * strlen (buffer));
bufor to zmienna stosu, do której zostały zapisane dane z klawiatury.

Myślę, że na pewno znajdą się ludzie, którzy zapytają: „Czy coś może tu być nie tak?”
Uwierz mi, może.

A co dokładnie - przeczytaj o wycięciu.

Trochę teorii - coś w rodzaju FaceBez.

Jeśli wiesz, przewiń do następnego nagłówka.

Łańcuch w C jest tablicą znaków, która w polubowny sposób zawsze powinna kończyć się „\\ 0” - znakiem końca linii. Ciągi znaków na stosie (statyczne) są deklarowane w następujący sposób:

Char str [n] \u003d (0);
n to rozmiar tablicy znaków, taki sam jak długość łańcucha.

Assignment (0) - "nulling" string (opcjonalnie, możesz zadeklarować bez niego). Wynik jest taki sam jak w przypadku funkcji memset (str, 0, sizeof (str)) i bzero (str, sizeof (str)). Służy do zapobiegania śmieciom w niezainicjowanych zmiennych.

Również na stosie możesz natychmiast zainicjować linię:

Char buf \u003d "domyślny tekst bufora \\ n";
Ponadto ciąg można zadeklarować jako wskaźnik i przydzielić mu pamięć na stercie:

Char * str \u003d malloc (rozmiar);
size - liczba bajtów, które przydzielamy dla ciągu. Takie łańcuchy nazywane są dynamicznymi (ze względu na fakt, że wymagany rozmiar jest obliczany dynamicznie + przydzielony rozmiar pamięci można w dowolnym momencie zwiększyć za pomocą funkcji realloc ()).

W przypadku zmiennej stosu użyłem notacji n do określenia rozmiaru tablicy, w przypadku zmiennej na stercie użyłem notacji rozmiaru. I to doskonale oddaje prawdziwą istotę różnicy między deklaracją na stosie a deklaracją z alokacją pamięci na stercie, ponieważ n jest zwykle używane, gdy mówimy o liczbie elementów. A rozmiar to zupełnie inna historia ...

Valgrind nam pomoże

W moim poprzednim artykule również o tym wspomniałem. Valgrind (dwa to trochę poradnika) to bardzo przydatny program, który pomaga programiście wyśledzić wycieki pamięci i błędy kontekstu - właśnie te rzeczy, które pojawiają się najczęściej podczas pracy z napisami.

Spójrzmy na małą listę, która implementuje coś podobnego do programu, o którym wspomniałem, i przeprowadźmy ją przez valgrind:

#zawierać #zawierać #zawierać #define HELLO_STRING "Witaj Habr! \\ n" void main () (char * str \u003d malloc (sizeof (char) * strlen (HELLO_STRING)); strcpy (str, HELLO_STRING); printf ("-\u003e \\ t% s" , str); wolny (str);)
A tak naprawdę wynik programu:

$ gcc main.c $ ./a.out -\u003e Witaj Habr!
Na razie nic niezwykłego. Teraz uruchommy ten program za pomocą valgrind!

$ valgrind --tool \u003d memcheck ./a.out \u003d\u003d 3892 \u003d\u003d Memcheck, wykrywacz błędów pamięci \u003d\u003d 3892 \u003d\u003d Copyright (C) 2002-2015 i GNU GPL "d, autorstwa Juliana Sewarda i innych. \u003d\u003d 3892 \u003d\u003d Używanie Valgrind-3.12.0 i LibVEX; uruchom ponownie z -h dla informacji o prawach autorskich \u003d\u003d 3892 \u003d\u003d Polecenie: ./a.out \u003d\u003d 3892 \u003d\u003d \u003d\u003d 3892 \u003d\u003d Nieprawidłowy zapis rozmiaru 2 \u003d\u003d 3892 \u003d \u003d pod adresem 0x4005B4: main (w /home/indever/prg/C/public/a.out) \u003d\u003d 3892 \u003d\u003d Adres 0x520004c ma 12 bajtów wewnątrz bloku o rozmiarze 13 alokacji "d \u003d\u003d 3892 \u003d\u003d w 0x4C2DB9D: malloc (vg_replace_malloc.c: 299) \u003d\u003d 3892 \u003d\u003d przez 0x400597: main (in /home/indever/prg/C/public/a.out) \u003d\u003d 3892 \u003d\u003d \u003d\u003d 3892 \u003d\u003d Nieprawidłowy odczyt rozmiaru 1 \u003d\u003d 3892 \u003d\u003d pod adresem 0x4C30BC4: strlen (vg_replace_strmem.c: 454) \u003d\u003d 3892 \u003d\u003d przez 0x4E89AD0: vfprintf (w /usr/lib64/libc-2.24.so) \u003d\u003d 3892 \u003d\u003d przez 0x4E90718: printf (w / usr / lib64 / libc-2.24.so) \u003d\u003d 3892 \u003d\u003d przez 0x4005CF: main (w /home/indever/prg/C/public/a.out) \u003d\u003d 3892 \u003d\u003d Adres 0x520004d to 0 bajtów po bloku o rozmiarze 13 przydziel "d \u003d\u003d 3892 \u003d\u003d przy 0x4C2DB9D: malloc (vg_replace_malloc.c: 299) \u003d\u003d 3892 \u003d\u003d przez 0x400597: main (in / home / indever / prg / C / public / a.out) \u003d\u003d 3892 \u003d\u003d -\u003e Witaj Habr! \u003d\u003d 3892 \u003d\u003d \u003d\u003d 3892 \u003d\u003d PODSUMOWANIE HEAP: \u003d\u003d 3892 \u003d\u003d w użyciu przy wyjściu: 0 bajtów w 0 blokach \u003d\u003d 3892 \u003d\u003d całkowite użycie sterty: 2 alokacje, 2 zwolnienia, 1037 przydzielonych bajtów \u003d\u003d 3892 \u003d \u003d \u003d\u003d 3892 \u003d\u003d Wszystkie bloki sterty zostały zwolnione - wycieki nie są możliwe \u003d\u003d 3892 \u003d\u003d \u003d\u003d 3892 \u003d\u003d Dla zliczeń wykrytych i usuniętych błędów, uruchom ponownie z: -v \u003d\u003d 3892 \u003d\u003d PODSUMOWANIE BŁĘDÓW: 3 błędy z 2 kontekstów (wyłączone: 0 z 0)
\u003d\u003d 3892 \u003d\u003d Wszystkie bloki sterty zostały uwolnione - żadne wycieki nie są możliwe - nie ma wycieków i to się podoba. Ale warto trochę spuścić oczy (choć, chcę zaznaczyć, to tylko podsumowanie, podstawowe informacje są trochę gdzie indziej):

\u003d\u003d 3892 \u003d\u003d PODSUMOWANIE BŁĘDÓW: 3 błędy z 2 kontekstów (pominięte: 0 z 0)
3 błędy. W 2 kontekstach. W tak prostym programie. W jaki sposób!?

To jest bardzo proste. Cała „sztuczka” polega na tym, że funkcja strlen nie bierze pod uwagę znaku końca wiersza „\\ 0”. Nawet jeśli wyraźnie określisz to w wierszu wejściowym (#define HELLO_STRING "Hello, Habr! \\ N \\ 0"), zostanie zignorowane.

Nieco powyżej wyniku wykonania programu, wiersze -\u003e Witaj, Habr! jest szczegółowy raport o tym, czego nie lubił nasz cenny valgrind i gdzie. Proponuję samemu przyjrzeć się tym kwestiom i wyciągnąć wnioski.

Właściwie poprawna wersja programu będzie wyglądać tak:

#zawierać #zawierać #zawierać #define HELLO_STRING "Witaj Habr! \\ n" void main () (char * str \u003d malloc (sizeof (char) * (strlen (HELLO_STRING) + 1)); strcpy (str, HELLO_STRING); printf ("-\u003e \\ Przebiegnijmy przez Valgrind:
{!LANG-4b2ee5de0e69e468c3855f7e241415cc!}

$ valgrind --tool \u003d memcheck ./a.out -\u003e Witaj Habr! \u003d\u003d 3435 \u003d\u003d \u003d\u003d 3435 \u003d\u003d PODSUMOWANIE HEAP: \u003d\u003d 3435 \u003d\u003d w użyciu przy wyjściu: 0 bajtów w 0 blokach \u003d\u003d 3435 \u003d\u003d całkowite użycie sterty: 2 alokacje, 2 zwolnienia, 1038 przydzielonych bajtów \u003d\u003d 3435 \u003d \u003d \u003d\u003d 3435 \u003d\u003d Wszystkie bloki sterty zostały zwolnione - wycieki nie są możliwe \u003d\u003d 3435 \u003d\u003d \u003d\u003d 3435 \u003d\u003d Dla zliczeń wykrytych i usuniętych błędów, uruchom ponownie z: -v \u003d\u003d 3435 \u003d\u003d PODSUMOWANIE BŁĘDÓW: 0 błędów z 0 kontekstów (wyłączone: 0 z 0)
W porządku. Brak błędów, +1 bajt przydzielonej pamięci pomogło rozwiązać problem.

Co ciekawe, w większości przypadków zarówno pierwszy, jak i drugi program będą działały tak samo, ale jeśli pamięć przydzielona dla linii, do której nie zmieścił się znak końcowy, nie była pusta, to funkcja printf () podczas wypisywania takiej linii również wypisze wszystkie śmieci po tej linii - wszystko będzie wypisywane, dopóki znak końca linii nie pojawi się na ścieżce printf ().

Jednak wiesz, (strlen (str) + 1) jest takim rozwiązaniem. Mamy 2 problemy:

  1. Ale co, jeśli musimy przydzielić pamięć dla łańcucha utworzonego za pomocą, na przykład, s (n) printf (..)? Nie popieramy argumentów.
  2. Wygląd. Linia deklaracji zmiennej wygląda po prostu okropnie. Niektórym facetom udaje się też wkręcić (zwęglać *) do malloc, jakby pisali pod plusami. W programie, w którym musisz regularnie przetwarzać linie, warto znaleźć bardziej eleganckie rozwiązanie.
Wymyślmy rozwiązanie, które zadowoli nas i Valgrind.

snprintf ()

int snprintf (char * str, size_t size, const char * format, ...); - rozszerzenie funkcji - sprintf, które formatuje napis i zapisuje go do wskaźnika przekazanego jako pierwszy argument. Różni się od sprintf () tym, że str nie zawiera więcej bajtów niż size.

Funkcja ma jedną ciekawą cechę - i tak zwraca rozmiar generowanego ciągu (z wyłączeniem znaku końca linii). Jeśli ciąg jest pusty, zwracane jest 0.

Jeden z problemów, które opisałem przy użyciu strlen, jest związany z funkcjami sprintf () i snprintf (). Załóżmy, że musimy napisać coś do str. Ostatni ciąg zawiera wartości innych zmiennych. Nasz wpis powinien wyglądać mniej więcej tak:

Char * str \u003d / * alokuj pamięć tutaj * /; sprintf (str, "Witaj,% s \\ n", "Habr!");
Powstaje pytanie: jak określić, ile pamięci należy zaalokować dla łańcucha str?

Char * str \u003d malloc (sizeof (char) * (strlen (str, "Witaj,% s \\ n", "Habr!") + 1)); - to nie pójdzie. Prototyp funkcji strlen () wygląda następująco:

#zawierać size_t strlen (const char * s);
const char * s nie oznacza, że \u200b\u200bciąg przekazany do s może być łańcuchem formatu ze zmienną liczbą argumentów.

W tym przypadku pomoże nam użyteczna właściwość funkcji snprintf (), o której wspomniałem powyżej. Przyjrzyjmy się kodowi następującego programu:

#zawierać #zawierać #zawierać void main () (/ * Ponieważ snprintf () nie bierze pod uwagę znaku końca linii, dodaj jego rozmiar do wyniku * / size_t required_mem \u003d snprintf (NULL, 0, "Witaj,% s! \\ n", "Habr") + sizeof ("\\ 0"); char * str \u003d malloc (required_mem); snprintf (str, required_mem, "Hello,% s! \\ n", "Habr"); printf ("-\u003e \\ t% s", str); wolny (str);)
Uruchom program w valgrind:

$ valgrind --tool \u003d memcheck ./a.out -\u003e Witaj Habr! \u003d\u003d 4132 \u003d\u003d \u003d\u003d 4132 \u003d\u003d PODSUMOWANIE HEAP: \u003d\u003d 4132 \u003d\u003d w użyciu przy wyjściu: 0 bajtów w 0 blokach \u003d\u003d 4132 \u003d\u003d całkowite wykorzystanie sterty: 2 alokacje, 2 zwolnienia, przydzielone 1041 bajtów \u003d\u003d 4132 \u003d \u003d \u003d\u003d 4132 \u003d\u003d Wszystkie bloki sterty zostały zwolnione - żadne wycieki nie są możliwe \u003d\u003d 4132 \u003d\u003d \u003d\u003d 4132 \u003d\u003d W celu zliczenia wykrytych i usuniętych błędów uruchom ponownie z: -v \u003d\u003d 4132 \u003d\u003d PODSUMOWANIE BŁĘDÓW: 0 błędów z 0 kontekstów (wyłączone: 0 z 0) $
W porządku. Mamy wsparcie dla argumentów. Ze względu na fakt, że jako drugi argument funkcji snprintf () przekazujemy zero, pisanie przez wskaźnik zerowy nigdy nie doprowadzi do Seagfault. Jednak pomimo tego funkcja nadal zwróci wymagany rozmiar ciągu.

Ale z drugiej strony musieliśmy dodać dodatkową zmienną i konstrukcję

Size_t required_mem \u003d snprintf (NULL, 0, "Witaj,% s! \\ N", "Habr") + sizeof ("\\ 0");
wygląda jeszcze gorzej niż strlen ().

Ogólnie rzecz biorąc, + sizeof ("\\ 0") można usunąć przez jawne określenie "\\ 0" na końcu ciągu formatującego (size_t required_mem \u003d snprintf (NULL, 0, "Witaj,% s! \\ N \0 "," Habr ");), ale nie zawsze jest to możliwe (w zależności od mechanizmu przetwarzania linii możemy przydzielić dodatkowy bajt).

Musimy coś zrobić. Pomyślałem trochę i zdecydowałem, że nadeszła godzina, by odwołać się do mądrości starożytnych. Opiszmy funkcję makra, która wywoła snprintf () z pustym wskaźnikiem jako pierwszym argumentem i null jako drugim. I nie zapominajmy o końcu linii!

#define strsize (args ...) snprintf (NULL, 0, args) + sizeof ("\\ 0")
Tak, może to być dla kogoś nowość, ale makra w C obsługują zmienną liczbę argumentów, a wielokropek mówi preprocesorowi, że określony argument funkcji makra (w naszym przypadku jest to argumenty) odpowiada kilku prawdziwym argumentom.

Sprawdźmy nasze rozwiązanie w praktyce:

#zawierać #zawierać #zawierać #define strsize (args ...) snprintf (NULL, 0, args) + sizeof ("\\ 0") void main () (char * str \u003d malloc (strsize ("Witaj,% s \\ n", "Habr! ")); sprintf (str," Witaj,% s \\ n "," Habr! "); printf (" -\u003e \\ t% s ", str); free (str);)
Biegnij z Valgrund:

$ valgrind --tool \u003d memcheck ./a.out -\u003e Witaj Habr! \u003d\u003d 6432 \u003d\u003d \u003d\u003d 6432 \u003d\u003d PODSUMOWANIE HEAP: \u003d\u003d 6432 \u003d\u003d w użyciu przy wyjściu: 0 bajtów w 0 blokach \u003d\u003d 6432 \u003d\u003d całkowite użycie sterty: 2 alokacje, 2 zwolnienia, przydzielone 1041 bajtów \u003d\u003d 6432 \u003d \u003d \u003d\u003d 6432 \u003d\u003d Wszystkie bloki sterty zostały zwolnione - nie ma wycieków \u003d\u003d 6432 \u003d\u003d \u003d\u003d 6432 \u003d\u003d W celu zliczenia wykrytych i usuniętych błędów uruchom ponownie z: -v \u003d\u003d 6432 \u003d\u003d PODSUMOWANIE BŁĘDÓW: 0 błędów z 0 kontekstów (wyłączone: 0 z 0)
Tak, nie ma błędów. Wszystko się zgadza. Valgrind jest szczęśliwy, a programista może wreszcie iść spać.

Ale na koniec powiem coś innego. Na wypadek, gdybyśmy musieli przydzielić pamięć dla dowolnego ciągu (nawet z argumentami), to już jest w pełni działające rozwiązanie pod klucz.

Chodzi o funkcję asprintf:

#define _GNU_SOURCE / * Zobacz feature_test_macros (7) * / #include int asprintf (char ** strp, const char * fmt, ...);
Pobiera wskaźnik do łańcucha (** strp) jako pierwszy argument i przydziela pamięć we wskaźniku, do którego została odwołana.

Nasz program napisany przy użyciu asprintf () wyglądałby tak:

#zawierać #zawierać #zawierać void main () (char * str; asprintf (& str, "Witaj,% s! \\ n", "Habr"); printf ("-\u003e \\ t% s", str); free (str);)
I faktycznie, w Valgrind:

$ valgrind --tool \u003d memcheck ./a.out -\u003e Witaj Habr! \u003d\u003d 6674 \u003d\u003d \u003d\u003d 6674 \u003d\u003d PODSUMOWANIE HEAP: \u003d\u003d 6674 \u003d\u003d w użyciu przy wyjściu: 0 bajtów w 0 blokach \u003d\u003d 6674 \u003d\u003d całkowite użycie sterty: 3 alokacje, 3 zwolnienia, przydzielone 1138 bajtów \u003d\u003d 6674 \u003d \u003d \u003d\u003d 6674 \u003d\u003d Wszystkie bloki sterty zostały zwolnione - nie ma wycieków \u003d\u003d 6674 \u003d\u003d \u003d\u003d 6674 \u003d\u003d W celu zliczenia wykrytych i usuniętych błędów, uruchom ponownie z: -v \u003d\u003d 6674 \u003d\u003d PODSUMOWANIE BŁĘDÓW: 0 błędów z 0 kontekstów (wyłączone: 0 z 0)
Wszystko jest w porządku, ale, jak widać, przydzielono w sumie więcej pamięci i teraz są trzy alokacje, a nie dwa. W słabych systemach wbudowanych ta funkcja jest niepożądana.
Dodatkowo, jeśli napiszemy man asprintf w konsoli, zobaczymy:

ZGODNE Z Te funkcje są rozszerzeniami GNU, a nie w C ani POSIX. Są również dostępne pod * BSD. Implementacja FreeBSD w przypadku błędu ustawia strp na NULL.

Wynika z tego jasno, że ta funkcja jest dostępna tylko w źródłach GNU.

Wniosek

Na koniec chcę powiedzieć, że praca ze łańcuchami w języku C jest bardzo złożonym tematem, który ma wiele niuansów. Na przykład, aby napisać „bezpieczny” kod do dynamicznej alokacji pamięci, nadal zaleca się użycie funkcji calloc () zamiast malloc () - calloc zatyka przydzieloną pamięć zerami. Cóż, lub po przydzieleniu pamięci użyj funkcji memset (). W przeciwnym razie śmieci, które pierwotnie leżały w przydzielonym obszarze pamięci, mogą powodować pytania podczas debugowania, a czasami podczas pracy z łańcuchem.

Ponad połowa moich kolegów programistów C (większość z nich to początkujący), którzy na moją prośbę rozwiązali problem alokacji pamięci dla łańcuchów, zrobili to w taki sposób, że ostatecznie doprowadziło to do błędów kontekstowych. W jednym przypadku - nawet do wycieku pamięci (cóż, osoba zapomniała zrobić free (str), komu się to nie zdarzyło). Właściwie to skłoniło mnie do stworzenia tego dzieła, które właśnie przeczytałeś.

Mam nadzieję, że komuś ten artykuł okaże się pomocny. Dlaczego się targowałem - żaden język nie jest prosty. Wszędzie ma swoje subtelności. Im więcej subtelności znasz języka, tym lepszy jest Twój kod.

Wierzę, że po przeczytaniu tego artykułu Twój kod będzie trochę lepszy :)
Powodzenia, Habr!

Biblioteka funkcji C i C ++ zawiera bogaty zestaw funkcji obsługi ciągów i znaków. Funkcje łańcuchowe działają na tablicach znaków zakończonych znakiem null. W języku C, aby używać funkcji ciągów, należy dołączyć plik nagłówkowy na początku modułu programu , a dla symbolicznych - plik nagłówkowy ... C ++ używa nagłówków do pracy z funkcjami łańcuchowymi i znakowymi i odpowiednio. W tym rozdziale dla uproszczenia używane są nazwy nagłówków C.

Ponieważ języki C i C ++ nie kontrolują automatycznie łamania swoich granic podczas wykonywania operacji na tablicach, cała odpowiedzialność za przepełnienie tablic spoczywa na barkach programisty. Zaniedbanie tych subtelności może doprowadzić do awarii programu.

W językach C i C ++ drukowalne znaki to te wyświetlane na terminalu. W środowiskach ASCII znajdują się one między spacją (0x20) a tyldą (OxFE). Znaki sterujące mają wartości od zera do Ox1F; zawierają one również symbol DEL (Ox7F).

Historycznie rzecz biorąc, argumentami funkcji symbolicznych są wartości całkowite, z których używany jest tylko najmniej znaczący bajt. Funkcje symboliczne automatycznie konwertują swoje argumenty na znaki bez znaku. Oczywiście możesz wywoływać te funkcje za pomocą argumentów symbolicznych, ponieważ symbole są automatycznie podnoszone do rangi liczb całkowitych, gdy funkcja jest wywoływana.

W tytule zdefiniowany jest typ size_t, który jest wynikiem operatora sizeof i jest rodzajem liczby całkowitej bez znaku.

C99 dodał kwalifikator ograniczenia do niektórych parametrów kilku funkcji pierwotnie zdefiniowanych w C89. Każda taka funkcja zostanie omówiona z jej prototypem używanym w środowisku C89 (a także w środowisku C ++), a parametry z atrybutem ogranicz zostaną odnotowane w opisie tej funkcji.

Lista funkcji

Sprawdzanie przynależności

isalnum - Sprawdź, czy znak jest alfanumeryczny
isalpha - Sprawdź, czy znak należy do liter
isblank - sprawdź, czy nie ma pustego znaku
iscntrl - Sprawdź, czy symbol należy do kontrolki
isdigit - Sprawdź, czy znak jest cyfrowy
isgraph - Sprawdź, czy znak można wydrukować, ale nie spację
islower - Sprawdź, czy znak jest małą literą
isprint - Sprawdź, czy znak można wydrukować
ispunct - Sprawdź, czy znak należy do znaków interpunkcyjnych
isspace - Sprawdź, czy znak jest białą spacją
isupper - Sprawdź, czy znak jest wielkimi literami
isxdigit - Sprawdź, czy znak jest szesnastkowy

Praca z tablicami znaków

memchr - Zapętlaj się po tablicy, aby znaleźć pierwsze wystąpienie znaku
memcmp - porównuje określoną liczbę znaków w dwóch tablicach
memcpy - kopiuje znaki z jednej tablicy do drugiej
memmove - kopiuje znaki z jednej tablicy do drugiej, biorąc pod uwagę nakładające się tablice
memset - Wypełnia określoną liczbę znaków w tablicy podaną

Manipulacja strunami

strcat - Dołącz kopię jednego ciągu do podanego
strchr - zwraca wskaźnik do pierwszego wystąpienia najmniej znaczącego bajtu danego parametru
strcmp - porównuje leksykograficznie dwa łańcuchy
strcoll - porównuje jeden ciąg z drugim zgodnie z setlocale
strcpy - Kopiuje zawartość jednego ciągu do drugiego
strcspn - zwraca ciąg bez określonych znaków
strerror - zwraca wskaźnik do ciągu zawierającego komunikat o błędzie systemu
strlen - zwraca długość łańcucha zakończonego znakiem null

DZWON

Są tacy, którzy czytają tę wiadomość przed tobą.
Zapisz się, aby otrzymywać najnowsze artykuły.
E-mail
Imię
Nazwisko
Jak chcesz przeczytać The Bell
Bez spamu