Ошибка при преобразовании в char * в объект моего пользовательского класса (mystring)

Определение количества различных подстрок

Пусть дана строка S длиной N, состоящая только из маленьких латинских букв. Требуется найти количество различных подстрок в этой строке.

Для решения переберём по очереди длину подстроки: L = 1 .. N.

Для каждого L мы построим массив хэшей подстрок длины L, причём приведём хэши к одной степени, и отсортируем этот массив. Количество различных элементов в этом массиве прибавляем к ответу.

Реализация:

string s; // входная строка
int n = (int) s.length();

// считаем все степени p
const int p = 31;
vector<long long> p_pow (s.length());
p_pow = 1;
for (size_t i=1; i<p_pow.size(); ++i)
	p_pow = p_pow * p;

// считаем хэши от всех префиксов
vector<long long> h (s.length());
for (size_t i=0; i<s.length(); ++i)
{
	h = (s - 'a' + 1) * p_pow;
	if (i)  h += h;
}

int result = 0;

// перебираем длину подстроки
for (int l=1; l<=n; ++l)
{
	// ищем ответ для текущей длины

	// получаем хэши для всех подстрок длины l
	vector<long long> hs (n-l+1);
	for (int i=0; i<n-l+1; ++i)
	{
		long long cur_h = h;
		if (i)  cur_h -= h;
		// приводим все хэши к одной степени
		cur_h *= p_pow;
		hs = cur_h;
	}

	// считаем количество различных хэшей
	sort (hs.begin(), hs.end());
	hs.erase (unique (hs.begin(), hs.end()), hs.end());
	result += (int) hs.size();
}

cout << result;

Создание и инициализация строки

Так как строка – это массив символов, то объявление и инициализация строки аналогичны подобным операциям с одномерными массивами.

Следующий код иллюстрирует различные способы инициализации строк.

Листинг 1.

  char str;
  char str1 = {'Y','o','n','g','C','o','d','e','r','\0'};
  char str2 = "Hello!";
  char str3[] = "Hello!";

Рис.1 Объявление и инициализация строк

В первой строке мы просто объявляем массив из десяти символов. Это даже не совсем строка, т.к. в ней отсутствует нуль-символ \0, пока это просто набор символов.

Вторая строка. Простейший способ инициализации в лоб. Объявляем каждый символ по отдельности. Тут главное не забыть добавить нуль-символ \0.

Третья строка – аналог второй строки

Обратите внимание на картинку. Т.к

символов в строке справа меньше, чем элементов в массиве, остальные элементы заполнятся \0.

Четвёртая строка. Как видите, тут не задан размер. Программа его вычислит автоматически и создаст массив символов нужный длины. При этом последним будет вставлен нуль-символ \0.

Создание свойства Read-only

Мы рассмотрели ранее, что свойство с одним методом принадлежит типу . Приведем пример создания такого рода свойств:

using System;
namespace Highload{
    class Human{
       private string fullname;
       private string loc;
       public Human(string a, string b){
          fullname = a;
          loc = b;
       }
       public string FullName{
          get{
             return fullname;
          }
       }
       public string Loc{
          get{
             return loc;
          }
       }
    }
    class Prog{
       static void Main(string[] args){
           Human u = new Human("Sheldon Cooper", "Pasadena");
           // ошибка, которую выдаст компилятор
           // u.FullName = "Howard Wolowitz";
           // get accessor will invoke
           Console.WriteLine("FullName: " + u.FullName);
           // get accessor will invoke
           Console.WriteLine("Loc: " + u.Loc);
       }
    }
}

Здесь мы применили только один метод доступа — , сделав тем самым наше свойство доступным только для чтения. Раскомментировав закомментированный код, мы получим ошибку компиляции из-за отсутствия возможности установить новое значение при помощи . 

Запустив нашу программу, мы получим следующий результат:

Перегрузки

Извлекает подстроку из данного экземпляра. Подстрока начинается в указанном положении символов и продолжается до конца строки.

Извлекает подстроку из данного экземпляра. Подстрока начинается с указанной позиции знака и имеет указанную длину.

Substring(Int32)

Извлекает подстроку из данного экземпляра. Подстрока начинается в указанном положении символов и продолжается до конца строки.

startIndex

Int32

Отсчитываемая от нуля позиция первого знака подстроки в данном экземпляре.

Возвращаемое значение

String

Строка, эквивалентная подстроке, которая начинается с в данном экземпляре, или Empty, если значение равно длине данного экземпляра.

Исключения

ArgumentOutOfRangeException

имеет значение меньше нуля или больше длины этого экземпляра.

Примеры

В следующем примере показано получение подстроки из строки.

В следующем примере метод используется Substring для разделения пар «ключ-значение», разделенных символом равенства («=»).

IndexOfМетод используется для получения позиции знака равенства в строке. Вызов метода извлекает имя ключа, которое начинается с первого символа в строке и расширяется для количества символов, возвращаемых при вызове IndexOf метода. Затем вызов метода извлекает значение, присвоенное ключу. Он начинается с одной позиции символа за знаком равенства и расширяется до конца строки.

Комментарии

Метод вызывается для извлечения подстроки из строки, которая начинается с указанной позиции символа и заканчивается в конце строки. Начальная позиции символа начинается с нуля; Иными словами, первый символ в строке находится по индексу 0, а не к индексу 1. Чтобы извлечь подстроку, которая начинается с указанной позиции символа и заканчивается до конца строки, вызовите метод.

Примечание

Этот метод не изменяет значение текущего экземпляра. Вместо этого он возвращает новую строку, которая начинается с позиции в текущей строке.

Чтобы извлечь подстроку, которая начинается с определенного символа или последовательности символов, вызовите метод, например IndexOf или, IndexOf чтобы получить значение . Во втором примере это показано. Он извлекает значение ключа, которое начинается с одной позиции символа после символа «=».

Если равен нулю, метод возвращает исходную строку без изменений.

Свойства и массив double

Рассмотрим пример по реализации свойства double-массива. Объявим:

  • поле — числовой массив 
  • несколько конструкторов класса;
  • индексатор, возвращающий нужные нам члены массива по порядковому номеру;
  • свойство
namespace Highload{
  class ArrDouble{
    double[] X; // массив 
    public ArrDouble(int size){
      // выделение ячейки памяти нашему массиву
      X = new double;
            for (int i = 0; i < size; i++)
        X = 0.0;
    } // заполнение массива нулевыми значениями

    public ArrDouble(double[] _X){
      X = new double;
      // копируем массив
      for (int i = 0; i < _X.Length; i++)
        X = _X;
    }
    
    public double this{
      get{
        if ((index >= 0) && (index < X.Length))
          return X;
        else
          return 0.0;
      }
    } // индексация

    */Объявление свойства Summary c методом get, находящим сумму всех членов массива и set, раздающим этим членам значения/*

    public double Summary{
      get{
        // суммируем элементы
        double summ = 0;
        for (int i = 0; i < X.Length; i++)
          summ += X;
        return summ;
      }
      set{
        // Равномерное распределение значений между членами массива
        double val = value/X.Length;
        for (int i = 0; i < X.Length; i++)
          X = val;
      }
    }
  }
  class Prog
  {
    static void Main(string[] args)
    {
      double[] X = { 1.0, 2.5, 2.0, 4.5, 0.0 }; 
      ArrDouble ad = new ArrDouble(X); // создание экземпляра ArrDouble

      double summary;
      summ = ad.Summ;
      Console.WriteLine("summ = {0}", summ);

      // заполняем ad единицами
      ad.Summ = 1.0 * X.Length;

      // проверяем
      double test;
      test = ad; // test = 1.0
      Console.WriteLine("test= {0}", test);
    }
  }
}

Выведет:summ = 10test = 1

В Summary вычисляет сумму всех членов массива, а — раздает им значение.

Изменение регистра

В процессе программирования может возникнуть необходимость изменить регистр текстового сообщения. Скажем, если вы разрабатываете голосовой помощник, сообщения, заложенные в логику вашего помощника, не должны реагировать на регистр — в этом случае можно использовать следующий метод:

string s = "Хочешь, я расскажу тебе секрет?";
string t = s.ToUpper(); // ХОЧЕШЬ, Я РАССКАЖУ ТЕБЕ СЕКРЕТ?

Результат выполнения кода C#

Обратная функция — , меняет регистр строк на нижний: 

string s = "Саша Сережа Елена Андрей Екатерина Мила";
string t = s.ToLower(); // саша сережа елена андрей екатерина мила

Результат выполнения кода C#

Еще один вариант изменения регистра осуществляется с помощью метода . Он используется в тех случаях, когда необходимо сделать заглавными первые буквы всех слов. Когда метод встречает слово, состоящее из заглавных букв, он считает это слово аббревиатурой и оставляет как есть. Для необходимо указывать пространство имен , которое содержит информацию о классах разных культур и регионов:

using System;
using System.Globalization;
public class Example
{
    public static void Main()
    {
        string[] values = { "сказка, рассказанная на ночь", "беЖиТ дорога подО Мной",
                          "Russia today",
                          "Возвращение Шерлока Холмса", "СССР и дети"};

        TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
        foreach (var value in values)
            Console.WriteLine("{0} --> {1}", value, ti.ToTitleCase(value));
    }
}

результат выполнения кода C#

Проверка на пустую строку

Для проверки, что строка пустая можно использовать сравнение со значением по умолчанию для строки «» или использовать функцию ПустаяСтрока. Данная функция вернет Истина если в строке только незначащие символы:

СтрокаОдин = «»;
ЭтоПустаяСтрока = СтрокаОдин = «»; //Истина

СтрокаСПробелом = » «;
ЭтоПустаяСтрока = СтрокаСПробелом = «»; //Ложь
ЭтоПустаяСтрока = ПустаяСтрока(СтрокаСПробелом); //Истина

1
2
3
4
5
6

СтрокаОдин= «»;

ЭтоПустаяСтрока= СтрокаОдин= «»;//Истина

 
СтрокаСПробелом= » «;

ЭтоПустаяСтрока= СтрокаСПробелом= «»;//Ложь

ЭтоПустаяСтрока= ПустаяСтрока(СтрокаСПробелом);//Истина

LPAD, RPAD

Эти функции используются, чтобы дополнить строку
какими-либо символами до определенной длины.

(left padding) используется для дополнения строки символами слева,
а (right padding) — для дополнения справа.

select lpad('1', 5, '0') n1,
       lpad('10', 5, '0') n2,
       lpad('some_str', 10) n2_1,
       rpad('38', 5, '0') n3,
       rpad('3', 5, '0') n4
from dual

Первый параметр в этой функции — строка, которую нужно дополнить,
второй — длина строки, которую мы хотим получить, а третий — символы, которыми
будем дополнять строку. Третий параметр не обязателен, и если его не указывать,
то строка будет дополняться пробелами, как в колонке .

Не используйте строки в стиле C

О строках в стиле C знать важно, потому что они используются во многих программах. Однако теперь, когда мы объяснили, как они работают, мы порекомендуем вам вообще избегать их, когда это возможно! Если у вас нет конкретной веской причины использовать строки в стиле C, используйте вместо них (определенную в заголовке )

проще, безопаснее и гибче. В редком случае, когда вам действительно нужно работать с фиксированными размерами буфера и строками в стиле C (например, для устройств с ограничением памяти), мы рекомендуем использовать хорошо протестированную стороннюю строковую библиотеку, разработанную для этой цели, или , который рассматривается в следующем уроке.

Правило

Используйте или (следующий урок) вместо строк в стиле C.

Особенности функций для работы со строками

Языки программирования могут включать специальные функции для работы со строками, избавляя тем самым программиста от необходимости писать собственные функции обработки строк. Например, часто требуется определить длину строки, и поэтому в языках предусмотрена функция, измеряющая ее длину.

В языке программирования C функции для работы со строками объявляются в заголовочном файле string.h, который надо не забывать подключать к своему исходному коду. Существует около двадцати функций для работы со строками. Среди них есть те, которые осуществляют поиск символов в строке, функции сравнения, копирования строк, а также более специфические. Перечень и описание большинства существующих на данный момент в языке C функций можно найти в приложении книги Б. Кернигана, Д. Ритчи «Язык программирования C. Второе издание».

Все функции, объявленные в string.h, в процессе своей работы могут изменять или не изменять одну из переданных по указателю строк. Это зависит от назначения функции. Однако большинство из них что-то возвращают: либо указатель на символ, либо целое. При этом если функция меняет один из своих параметров и ради этого была вызвана, тогда то, что она возвращает, можно проигнорировать (т.е. ничему не присваивать в вызывающей функции).

Например, функция имеет такое объявление: . Она копирует строку, на которую указывает второй параметр, в строку, на которую указывает первый параметр. Таким образом первый параметр изменяется. Кроме того, функция возвращает указатель на первый символ строки:

char s110, s210;
char *s3;
s3 = s2;
 
gets(s1);
s3 = strcpy(s2,s1);
puts(s2);
puts(s3);
printf("%p, %p\n", s2, s3);

Здесь s2 и s3 указывают на один и тот же символ ( выводит одинаковые адреса). Однако то, что возвращает , нельзя присвоить массиву. Результат работы этой функции обычно ничему не присваивают; бывает достаточно того, что она просто изменяет одну из переданных по указателю строк.

Другое дело, такие функции как или , которые не изменяют параметры, а вызываются ради результата. Функция сравнивает две строки-аргумента по буквам (лексикографически) и возвращает 0, -1 или 1. Например, вызов вернет 1, т.к. код буквы ‘y’ больше буквы ‘d’. Вызов вернет -1, т.к. первый аргумент лексикографически меньше второго.

Чтение строк

Для того, чтобы запросить у пользователя строку, необходимо создать буфер. Размер буфера должен быть выбран заранее, так, чтобы введённое слово в нём
поместилось. При считывании строк есть опасность того, что пользователь введёт данных больше, чем позволяет буфер. Эти данные будут считаны и помещены в память, и
затрут собой чужие значения. Таким образом можно провести атаку, записав нужные байты, в которых, к примеру, стоит переход на участок кода с вредоносной программой, или
логгирование данных.

#include <conio.h>
#include <stdio.h>
 
void main() {
    char buffer;

	scanf("%19s", buffer);
	printf("%s", buffer);

	getch();
}

В данном случае количество введённых символов ограничено 19, а размер буфера на 1 больше, так как необходимо хранить терминальный символ.
Напишем простую программу, которая запрашивает у пользователя строку и возвращает её длину.

#include <conio.h>
#include <stdio.h>
 
void main() {
    char buffer;
	unsigned len = 0;

	scanf("%127s", buffer);

	while (buffer != '\0') {
		len++;
	}

	printf("length(%s) == %d", buffer, len);

	getch();
}

Так как числовое значение символа ‘\0’ равно нулю, то можно записать

while (buffer != 0) {
	len++;
}

Или, ещё короче

while (buffer) {
	len++;
}

Теперь напишем программу, которая запрашивает у пользователя два слова и сравнивает их

#include <conio.h>
#include <stdio.h>
 
/*
Результатом сравнения будет число
0 если слова равны
1 если первое слово больше второго в лексикографическом порядке
-1 если второе слово больше
*/

void main() {
    char firstWord;	//Первое слово
	char secondWord;	//Второе слово
	unsigned i;				//Счётчик
	int cmpResult = 0;		//Результат сравнения

	scanf("%127s", firstWord);
	scanf("%127s", secondWord);

	for (i = 0; i < 128; i++) {
		if (firstWord > secondWord) {
			//Больше даже если второе слово уже закончилось, потому что
			//тогда оно заканчивается нулём
			cmpResult = 1;
			break;
		} else if (firstWord < secondWord) {
			cmpResult = -1;
			break;
		}
	}

	printf("%d", cmpResult);

	getch();
}

Так как каждая буква имеет числовое значение, то их можно сравнивать между собой как числа. Кроме того, обычно (но не всегда!) буквы в таблицах кодировок расположены по алфавиту. Поэтому сортировка по числовому значению также будет и сортировкой по алфавиту.

Q&A

Всё ещё не понятно? – пиши вопросы на ящик

Создание и инициализация объекта класса String

Существует несколько способов создать объект класса String и проинициализировать его. Рассмотрим варианты, которые доступны в C#. Наиболее распространенный способ сделать эту операцию – это присвоить строковое значение переменной без явного вызова конструктора, так, как мы это делали в предыдущем разделе:

string s5 = "test1";
var s6 = "test2";

Для дословного представления строки, для того чтобы проигнорировать управляющие последовательности, используйте префикс @ перед значением. Сравните вывод следующей конструкции:

Console.WriteLine("first line\nSecond line");

С вариантом:

Console.WriteLine(@"first line\nSecond line");

Если требуется подготовить строковое значение с использованием набора переменных, то можно воспользоваться статическим методом Format класса String, либо префиксом $

int age = 27;
Console.WriteLine(String.Format("Age: {0}", age));
Console.WriteLine("");
Console.WriteLine($"Age: {age}");
Console.WriteLine("");

Можно явно вызвать конструктор типа c передачей в него параметров. Самый простой вариант – это передать строку:

string s7 = new string("test3");

В качестве параметра может выступать массив Char элементов:

char[] charArray = {'H', 'e', 'l', 'l', 'o'};
string s8 = new string(charArray);

Ещё вариант – это указать элемент типа char и количество раз, которое его нужно повторить:

string s9 = new string('O', 10); // "OOOOOOOOOO"

Для создания строки также можно использовать указатели на Char* и SByte*, но в данном уроке эта тема рассматриваться не будет.

Пример 1: для чтения слова

Программа на C++ для отображения строки, введенной пользователем:

#include <iostream>
using namespace std;

int main()
{
    char str;

    cout << "Enter a string: ";
    cin >> str;
    cout << "You entered: " << str << endl;

    cout << "\nEnter another string: ";
    cin >> str;
    cout << "You entered: "<<str<<endl;

    return 0;
}

Выход:

Enter a string: C++
You entered: C++

Enter another string: Programming is fun.
You entered: Programming

Обратите внимание, что во втором примере отображается только «Programming» вместо «Programming is fun». Это потому, что оператор извлечения >> работает, как scanf() в C++ и считает, что промежуток ” ” имеет завершающий символ

Это потому, что оператор извлечения >> работает, как scanf() в C++ и считает, что промежуток ” ” имеет завершающий символ.

Обзор классов строк

Весь строковый функционал стандартной библиотеки находится в заголовочном файле. Чтобы использовать его, просто включите заголовок :

На самом деле в заголовке есть 3 разных класса строк. Первый – это шаблонный базовый класс с именем :

Вы не будете работать с этим классом напрямую, поэтому пока не беспокойтесь о том, что это за и . Значений по умолчанию будет достаточно почти во всех мыслимых случаях.

Стандартная библиотека предоставляет две разновидности :

Это два класса, которые вы непосредственно будете использовать. используется для стандартных строк ASCII и UTF-8. используется для строк с расширенными символами / Unicode (UTF-16). Для строк UTF-32 нет встроенного класса (хотя вы можете расширить из свой собственный класс, если он вам нужен).

Хотя вы будете напрямую использовать и , весь строковый функционал реализован в классе . и могут получить доступ к этому функционалу напрямую благодаря шаблону. Следовательно, все представленные функции будут работать как для , так и для . Однако, поскольку является шаблонным классом, это также означает, что, если вы сделаете что-то синтаксически неверное со или , компилятор выдаст ужасно выглядящие ошибки шаблона. Не пугайтесь этих ошибок; они выглядят намного хуже, чем они есть на самом деле!

Вот список всех функций в строковом классе. Для обработки различных типов входных данных большинство этих функций имеют несколько разновидностей, которые мы рассмотрим более подробно в следующих уроках.

Функция Действие
Создание и уничтожение
конструктор Создает или копирует строку
деструктор Уничтожает строку
Размер и вместимость
Возвращает количество символов, которые могут храниться без перераспределения памяти
Возвращает логическое значение, указывающее, пуста ли строка
, Возвращает количество символов в строке
Возвращает максимальный размер строки, которая может быть размещена
Увеличить или уменьшить вместимость строки
Доступ к элементам
, Доступ к символу по определенному индексу
Модификация
, Присваивает новое значение строке
, , Добавляет символы в конец строки
Вставляет символы в строку по произвольному индексу
Удаляет все символы в строке
Стирает символы по произвольному индексу в строке
Заменяет символы с произвольным индексом на другие символы
Расширение или сжатие строки (обрезает или добавляет символы в конце строки)
Меняет местами значения двух строк
Ввод и вывод
, Считывает значения из входного потока в строку
Записывает значение строки в выходной поток
Возвращает содержимое строки как строку в стиле C с завершающим нулем
Копирует содержимое (не оканчивающееся нулем) в массив символов
То же, что . Неконстантная перегрузка позволяет выполнять запись в возвращаемую строку
Сравнение строк
, Сравнивает, равны или неравны две строки (возвращает )
, , , Сравнивает, являются ли две строки меньше/больше друг друга (возвращает )
Сравнивает, равны или неравны две строки (возвращает -1, 0 или 1)
Подстроки и конкатенация
Объединяет две строки
Возвращает подстроку
Поиск
Найти индекс первого символа/подстроки
Найти индекс первого символа из набора символов
Найти индекс первого символа, не входящего в набор символов
Найти индекс последнего символа из набора символов
Найти индекс последнего символа, не входящего в набор символов
Найти индекс последнего символа/подстроки
Поддержка итераторов и распределителей памяти (аллокаторов)
, Поддержка итератора прямого направления для начала/конца строки
Возвращает распределитель
, Поддержка итератора обратного направления для начала/конца строки

Хотя строковые классы библиотеки STL предоставляют множество функций, есть несколько заметных упущений:

  • поддержка регулярных выражений;
  • конструкторы для создания строк из чисел;
  • функции изменения регистра на верхний/нижний;
  • сравнение без учета регистра;
  • разбиение строки на массив;
  • простые функции для получения левой или правой части строки;
  • обрезка пробелов в начале и конце строки;
  • форматирование строки в стиле ;
  • преобразование из UTF-8 в UTF-16 или наоборот.

Для большинства из них вам придется либо написать свои собственные функции, либо преобразовать вашу строку в строку в стиле C (используя ) и использовать функции C, которые предлагают эту функциональность.

В следующих уроках мы более подробно рассмотрим различные функции класса . Хотя в наших примерах мы будем использовать , всё в равной степени применимо и к .

$ — интерполяция строк

Начиная с C# 6 появилась возможность строить интерполированную строку, формат которой позволяет более просто, по сравнению с составным форматированием, рассмотренным нами выше, создавать строки. Интерполированная строка содержит специальные выражения интерполяции, они похожи на элементы форматирования. Выражения интерполяции имеют следующий вид:

{<interpolationExpression>}

где interpolationExpression – элемент, значение, которого будет интегрироваться в строку;

alignment – выравнивание;

formatString – формат (см. форматирование строк).

Примеры работы с интерполированной строкой:

int n1 = 45678;
double d1 = 123.34567;
bool b1 = true;
string sv = "test";
Console.WriteLine($"int val: {n1}, double val: {d1:#.###}");
Console.WriteLine($"bool val: {b1}, string val: {sv}");

Многострочная строка

Для получения строки из многострочной строки по ее номеру можно использовать метод СтрПолучитьСтроку. Для подсчета строк в многострочной строке — СтрЧислоСтрок:

СтрокаОдин = «Многострочкая строка 1» + Символы.ПС + «Многострочкая строка 2»;
Колво = СтрЧислоСтрок(СтрокаОдин); //2
ПерваяСтрока = СтрПолучитьСтроку(СтрокаОдин, 1); //Многострочкая строка 1
ВтораяСтрока = СтрПолучитьСтроку(СтрокаОдин, 2); //Многострочкая строка 2

1
2
3
4

СтрокаОдин= «Многострочкая строка 1″+Символы.ПС+»Многострочкая строка 2»;

Колво= СтрЧислоСтрок(СтрокаОдин);//2

ПерваяСтрока= СтрПолучитьСтроку(СтрокаОдин,1);//Многострочкая строка 1

ВтораяСтрока= СтрПолучитьСтроку(СтрокаОдин,2);//Многострочкая строка 2

Сравнение строк

Задача сравнения строк выполняется методом . Результатом такого сравнения является число, принимающее значение 1, 0 или -1: 

  • 1 — сравниваемый текст начинается с символа, раньше по алфавиту;
  • 0 — означает, что строки идентичны;
  • -1 — когда сравниваемый текст начинается с символа позже по алфавиту.
class appz
    {
        static void Main(string[] args)
        {
            string first = "Highload";
            string second = "Zighload";

            int t = first.CompareTo(second);
            // t = -1
            Console.WriteLine(t);
            Console.ReadLine();
        }
    }

Результат выполнения кода C#

Строки можно сравнивать также методом

String.Compare("Stroka1", "Stroka2");

Когда в задачу не входит учитывание регистра, в методе используется аргумент

String.Compare("stroka1", "Stroka2", true);

Еще один прием для сравнения строк — метод . Он записывается либо с одним аргументом, либо с двумя:

string city = "Kiyv";
bool sravnenie;
sravnenie = city.Equals("Kiyv");
Console.WriteLine(sravnenie);
sravnenie = city.Equals("Kiev");
Console.WriteLine(sravnenie); 
sravnenie = String.Equals(city, "Kiyv");
Console.WriteLine(sravnenie);
sravnenie = String.Equals(city, "Kiev"); 
Console.WriteLine(sravnenie);
Console.ReadLine();

Результат выполнения кода C#

Передача строки в функцию

Передача строки в функцию ничем не отличается от передачи туда массива чисел:

void change (char *s) {
    for (;*s != '\0'; s++)
        (*s)++;
}

В этом примере функция принимает в качестве параметра указатель на символ. В теле функции значение указателя инкрементируется, указывая на следующий символ массива. В теле цикла инкрементируется значение, которое находится по адресу, который содержит указатель.

Объявите в программе три массива символов. Данные для двух из них получите с помощью вызовов функции . Третий массив должен содержать результат конкатенации (соединения) двух введенных строк. Напишите функцию, которая выполняет конкатенацию строк.

Конверсия число-строка и строка-число.

int atoi (const char * str);

Переводит строку в целое

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

void main() {
	char ex1[] = "   23  ";
	char ex2[] = "rule43";
	char ex3[] = "21st of May";
	printf("%d\n", atoi(ex1));
	printf("%d\n", atoi(ex2));
	printf("%d\n", atoi(ex3));
	getch();
}
double atof (const char* str);

Переводит строку в число типа double.

long int atol ( const char * str );

Переводит строку в число типа long

Все функции такого рода имеют название XtoY, где X и Y — сокращения типов. A обозначает ASCII. Соответственно, имеется обратная функция itoa (больше нет:)).
Таких функций в библиотеке stdlib.h очень много, все их рассматривать не хватит места.

Функция strtok()

С помощью функции можно разбить строку на отдельные части (лексемы). Объявление этой функции выглядит так . При первом вызове функции в качестве первого параметра указывается строка, которую требуется разбить. Вторым параметром указывается строка-разделитель. При последующих вызовах функции для этой же строки первым параметром должен быть NULL, т.к. функция уже «запомнила» с чем работает. Рассмотрим пример:

char str = "one, two, three, four";
char *sp;
 
sp = strtok(str, ", ");
while (sp) {
    puts(sp);
    sp = strtok(NULL, ", ");
}

В результате выполнения данного кода на экран в столбик выводятся слова:

one
two
three
four
five

При первом вызове в функцию передается указатель на первый символ массива и строка-разделитель. После этого вызова массив str изменяется, в нем остается только слово «one», также функция возвращает указатель на это слово, который присваивается sp.

Хотя мы потеряли остаток массива в вызывающей функции, однако внутри сохраняется указатель на остаток массива. Когда передается NULL, функция «знает», что надо работать с этим «хвостом».

Поиск

void* memchr (void * ptr, int value, size_t num);

Проводит поиск среди первых num байтов участка памяти, на который ссылается ptr, первого вхождения значения value, которое трактуется как unsigned char. Возвращает указатель на найденный элемент, либо NULL.

#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>

void main() {
	char str[] = "Hello World!";
	char *ptr = NULL;

	ptr = (char*) memchr(str, '\0', 4000);
	if (ptr != NULL) {
		printf("first zero byte address is %p, strlen = %d", ptr, ptr - str);
	} else {
		printf("no null byte in memory block");
	}
	getch();
}
char* strchr (char * str, int character);

Возвращает указатель на место первого вхождения character в строку str. Очень похожа на функцию memchr, но работает со строками, а не с произвольным блоком памяти.

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

Возвращает адрес первого вхождения любой буквы из строки str2 в строке str1. Если ни одно включение не найдено, то возвратит длину строки.

Пример — найдём положение всех гласных в строке

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main() {
	char str[] = "So if you want to love me\n"
				 "Then darling don't refrain\n"
				 "Or I'll just end up walking\n"
				 "In the cold November rain\n";
	char vowels[] = "aeiouy";
	int i;

	i = 0;
	while (str) {
		i = i + strcspn(&str, vowels);
		printf("%d ", i);
		i++;
	}
	getch();
}

Здесь обратите внимание на строку i++ после printf. Если бы её не было, то strcspn возвращал бы всегда 0, потому что в начале строки стояла бы гласная, и произошло зацикливание.

Для решения этой задачи гораздо лучше подошла функция, которая возвращает указатель на первую гласную.

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

Функция очень похожа на strcspn, только возвращает указатель на первый символ из строки str1, который есть в строке str2.
Выведем все гласные в строке

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main() {
	char str[] = "Cos' it's a bittersweet symphony this life...\n"
		         "Trying to make ends meet, you're a slave to the money then you die.";
	char vowels[] = "aeiouy";
	char *p = NULL;

	p = strpbrk(str, vowels);
	while (p) {
		printf("%c ", *p);
		p++;
		p = strpbrk(p, vowels);
	}
	getch();
}
char* strrchr (char * str, int character );

Возвращает указатель на последнее вхождение символа в троку.

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

Возвращает длину куска строки str1, начиная от начала, который состоит только из букв строки str2.

Пример — вывести число, которое встречается в строке.

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main() {
	char str[] = "on 21st of May";
	char nums[] = "0123456789";
	char number;
	uintptr_t i;

	//Определяем, где начинаются цифры
	size_t start = strcspn(str, nums);
	//Определяем, где они заканчиваются, относительно start
	size_t end = strspn(&str, nums);
	
	for (i = 0; i < end; i++) {
		printf("%c", str);
	}

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

Возвращает указатель на первое вхождение строки str2 в строку str1.

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main() {
	char str[] = "I'll drown my beliefs\n"
				 "To have you be in peace\n"
				 "I'll dress like your niece\n"
				 "And wash your swollen feet\n";
	char niece[] = "niece";
	
	char* p = strstr(str, niece);
	printf("%s", p);
	getch();
}
char* strtok (char * str, const char * delimiters);

Разбивает строку на токены. В данном случае токенами считаются последовательности символов, разделённых символами, входящими в группу разделителей.

#include <stdio.h>
#include <conio.h>
#include <string.h>

void main() {
	char str[] = "After working in India during the late 1970s and 1980s, "
		"Shankar's profile in the West began to rise again in the mid-1990s "
		"as his music found its way into club DJ sets, particularly in London.";
	char delim[] = " \t\n\,.-";
	char *p = strtok(str, delim);
    while (p != NULL) {
        printf ("%s\n",p);
        p = strtok (NULL, delim);
    }
	getch();
}

Неформатированные ввод из стандартного потока и вывод в стандартный поток

С помощью функции можно легко вывести на экран строку, содержащую пробелы:

printf("%s", "Hello world");

С другой стороны, ввести строку произвольной длины, содержащую пробелы в неизвестных местах, исключительно с помощью функции невозможно. Для любой символ пустого пространства является сигналом завершения ввода очередных данных, если только не производится считывание символа.

На помощь может прийти функция , осуществляющая посимвольный ввод данных:

int i;
char str20;
 
for (i=; (stri=getchar())!='\n'; i++);
stri = '\0';
 
printf("\n%s\n", str);

В заголовке цикла возвращает символ, далее записываемый в очередную ячейку массива. После этого элемент массива сравнивается с символом ‘\n’. Если они равны, то цикл завершается. После цикла символ ‘\n’ в массиве «затирается» символом ‘\0’. В условии цикла должна быть также предусмотрена проверка на выход за пределы массива; чтобы не усложнять пример, опущена.

Однако в языке программирования C работать со строками можно проще. С помощью функций стандартной библиотеки и получают строку из стандартного потока и выводят в стандартный поток. Буква s в конце слов gets и puts является сокращением от слова string (строка).

В качестве параметров обе функции принимают указатель на массив символов (либо имя массива, либо указатель).

Функция помещает полученные с ввода символы в указанный в качестве аргумента массив. При этом символ перехода на новую строку, который завершает ее работу, игнорируется.
Функция выводит строку на экран и при этом сама добавляет символ перехода на новую строку. Простейший пример использования этих функций выглядит так:

char str20;
 
gets(str);
puts(str);

Итак, если вы работаете со строками, а не другими типами данных, при этом нет необходимости выполнять их посимвольную обработку, то удобнее пользоваться функциями и . (Однако функция gets() считается опасной и была выпилена из версии языка C11.)

Форматированный ввод и вывод в буфер

Можно также выделить две функции sprintf и sscanf. Они отличаются от printf и scanf тем, что выводят данные и считывают их из буфера. Это, например, позволяет переводить строку в число и число в строку. Например

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

void main() {
	int i;
	float f;
	char buffer;
	scanf("%d", &i);
	scanf("%f", &f);
	sprintf(buffer, "%d", i);
	printf("%s\n", buffer);
	sprintf(buffer, "%.3f", f);
	printf("%s", buffer);
	getch();
}

Вообще, работа со строками — задача более глобальная, чем можно себе представить. Так или иначе, практически каждое приложение связано с обработкой текста.

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: