Главная

Популярная публикация

Научная публикация

Случайная публикация

Обратная связь

ТОР 5 статей:

Методические подходы к анализу финансового состояния предприятия

Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века

Ценовые и неценовые факторы

Характеристика шлифовальных кругов и ее маркировка

Служебные части речи. Предлог. Союз. Частицы

КАТЕГОРИИ:






Описание строк и примеры строковых функции




Строки есть массивы типа char, оканчивающиеся спецсимволом \0

char string[20];

string[0] = 'П';

string[1] = 'р';

string[2] = 'и';

string[3] = 'в';

string[4] = 'е';

string[5] = 'т';

string[6] = '\0';

printf("%s\n", string);

%s - формат для печати СТРОК.

ПОЧЕМУ ДЛЯ СТРОК ИЗОБРЕЛИ СИМВОЛ "ПРИЗНАК КОНЦА"?

Строка - это ЧАСТЬ массива букв.

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

символов). Есть три решения:

(1) В отдельной переменной. Ее следует передавать во все

функции обработки данной строки (причем она может изменяться).

char str[32]; /* массив для строки */

int slen; /* брать первые slen букв в этом массиве */

...

func(str, &slen); /* ДВА аргумента для передачи ОДНОЙ строки */

...

Этот подход работоспособен, но строка разбивается на два

объекта: сам массив и переменную для его длины. Неудобно.

(2) Хранить текущую длину в элементе str[0],

а буквы - в str[1]... итд.

Плохо тем, что в str[0] можно хранить лишь числа от 0 до 255,

и если строка длиннее - то такой подход неприменим.

(3) Не хранить длину НИГДЕ, а ввести символ-признак конца строки.

Теперь в

func(str); /* ОДИН аргумент - сам массив */

передается только сам массив, а его текущая длина может быть

при нужде вычислена при помощи некоей функции, вроде такой:

int strlen(char s[]){ /* функция от массива букв */

int counter = 0; /* счетчик и одновременно индекс */

while(s[counter]!= '\0') /* пока не встретился признак конца текста */

counter++; /* посчитать символ */

return counter; /* сколько символов, отличных от '\0' */

}

Тут никаких ограничений нет. Именно этот подход и был избран

в языке Си, хотя в принципе можно самому пользоваться и другими.

Строки будем описывать и работать с ними, как с массивами символов.

Примеры описаний:


<SPAN lang=EN-US style="mso-ansi-language: EN-US"> char s[10];
char s[10]="123";
char</SPAN> *s:="123";
<SPAN lang=EN-US style="mso-ansi-language: EN-US"> char *s={</SPAN>'1','2','3','<SPAN lang=EN-US style="mso-ansi-language: EN-US">\0</SPAN>'};
<SPAN lang=EN-US style="mso-ansi-language: EN-US"> char *s={</SPAN>'1','2','3',0};
<SPAN lang=EN-US style="mso-ansi-language: EN-US"> char *s=</SPAN>{'1','2','3'};

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

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

Третий пример отличается от второго тем, что в памяти выделяется ровно четыре байта под строку s, Обратиться к s [3] мы еще можем (это символ ' \0'), а вот запись s [4 ], хотя у компилятора к ней не будет претензий, уже неверна. Нет у строки s такого элемента!

Четвертый и пятый примеры полностью эквивалентны третьему, отличаются они лишь тем, как записан символ с кодом 0. Но это совершенно безразлично.

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

Отметим, что присваивать значение строке целиком можно только при инициализации в описании (как и в случае с массивами). Так, как показано ниже, делать нельзя: <SPAN lang=EN-US style="mso-ansi-language: EN-US">unsigned char s[10]; s="123" или <SPAN lang=EN-US style="mso-ansi-language: EN-US">unsigned char *s; </SPAN><SPAN lang=EN-US>s="123";</SPAN></SPAN>

Функции работы со строками <string.h>

Имеются 2 группы функций, работающих со строками, они определяются в <String.h>. Имена функций первой группы начинаются с str, второй с mem. Функции сравнения рассматривают аргументы как массивы элементов типа unsigned char.

В таблице переменные s и t имеют тип char*, сs и st -const char*, n-size_t, а c- значение типа int, приведенное к char.

Последовательные вызовы strtok разбивают строку s на лексемы. Ограничителем лексемы служит любой символ из строки st. В первом вызове указатель s не равен NULL. Функция находит в строке s первую лексему, состоящую из символов, не входящтх в st, ее работа заканчивается тем, что поверх следующего символа пишется '\0' и возвращается указатель на лексему. Каждый последующий вызоу, в котором указатель s равен NULL, возвращает указатель на следующую лексему, которую функция будет искать сразу за концом предыдущей. Функция strtok возвращает NULL, если далее никакой лексемы не обнаружено. Параметр st от вызова к вызову может варьироваться.


 

strcpy(s,ct) копирует строку ct в строку s, включая '\0', возвращает s
strncpy(s,ct,n) копирует не более n символов строки ct в строку s, возвращает s. Дополняет результат символами '\0', если символов в ct меньше n
strcat(s,ct) приписывает ct к s. возвращает s
strncat(s,ct,n) приписывает не более n стмволов ct к s, завершая s стмволом '\0', возвращает s
strcmp(cs,ct) сравнивает cs и ct. возвращает <0, если cs<ct, 0 если равны, и >0, если cs>ct. сравнение лексикографическое, те cs<ct, если первый несовпавший символ в cs арифметически меньше соответствующего стмвола из ct
strncmp(cs,ct) сравнивает не более n символов cs и ct. возвращает <0, если cs<ct, 0 если равны, и >0, если cs>ct. сравнение лексикографическое, те cs<ct, если первый несовпавший символ в cs арифметически меньше соответствующего стмвола из ct
strchr(cs,c) возвращает указатель на первое вхождение c в cs, елси такогвого не оказалось, NULL
strrchr(cs,c) возвращает указатель на последнее вхождение c в cs, елси такогвого не оказалось, NULL
strspn(cs,ct) возвращает длину начального сегмента cs, состоящего из символов, входящих в строку ct
strcspn(cs,ct) возвращает длину начального сегмента cs, состоящего из символов, не входящих в строку ct
strpbrk(cs,ct) возвращает указатель в cs на первый символ, который совпал с одним из символов, входящих в ctили NULL
strstr(cs,ct) возвращает указатель в cs на первое вхождение ct в cs или NULL
strlen(cs) длина строки
strerror(n) возвращает указатель на зависящую от реализвации строку, соотв. номеру ошибки n
strtok(s,ct) ищет в s лексему, ограниченную символами из ct

 

Функции mem предназначены для манипулирования с объектами как с массивами символов, их назначение - получить интерфейсы к эффективным программам. В таблице s и t имеют тип void*, Cs и ct-const void*. n-size_t,c-int приведенное к char

memcpy(s,ct,n) копирует n символов из ct в d и возвращает s
memmove(s,ct,n) копирует n символов из ct в d и возвращает s, к тому же работает в лучае "перекрывающихся объектов"
memcmp(cs,ct,n) сравнивает первые n символов cs и ct, резтат тот же, что strcmp
memchr(cs,c,n) возвращает указатель на первое вхождение символа c в cs или, если среди первых n символов c не встретилось, то NULL
memset(s,c,n) размещает символ c в первых n похициях строки s и возвращает s

 


Задание на строки:

1. Ввести 3 строки: str1 (с помощью scanf) str2 (с помощью gets) и str3="Вася"/

- определить длину каждой строки и вывести

- слить 3 строки (через пробелы) в предложение и поместить в строку Str4. Вывести саму строку и ее длину

- скопировать в новую строку str5 первый слог строки str3 5 раз. Вывести и определить длину получившейся строки

- определить длину начального сегмента строки str3, входящего в строку str5

2. Задание на массивы:

- определить в одномерном массиве три чисал, стоящие подряд, сумма которых максимальна.

- определить и вывести на экран в двумерном массиве столбеб, сумма элементов которого минимальна

- если в двумерном массиве етсь отрицательное число, то заменить всю строку с этим числом на 0

 

 


#include <string.h>

#include <stdio.h>

#include <conio.h>

main()

{

char name[15], soname[25], s1[20], s2[30],s3[10];

char u;

clrscr();

int i,k;

printf ("введите первую строку\n");

scanf("%s", name);

k=strlen(name);

printf("длина первой строки %d\n", k);

printf ("введите вторую строку\n");

scanf("%s", soname);

printf ("привет, %s %s\n", name, soname);

strcpy(s1,"это");

strcat(s1, soname);

printf("слияние строк %s\n", s1);

strcpy(s1," Вас");

i=strcmp(name,s1);

if (i==0) strcpy(s2,"строки равны");

else

if (i>0) strcpy(s2,"первая больше второй");

else strcpy(s2,"вторая больше первой");

printf("результат сравнения строк %s\n", s2);

strncpy(s3,soname,2);

printf("копирование n символов строки %s \n",s3);

i=strspn(name,s1);

printf("длина нач. сегмента name, сост. из символов входящих в s1 %d\n",i);

i=strcspn(name,s1);

printf("длина нач. сегмента name, сост. из символов не входящих в s1 %d\n",i);

 

}


Указатели

Указатель - это переменная, содержащая адрес другой пе­ременной. указатели очень широко используются в языке "C". Это происходит отчасти потому, что иногда они дают единст­венную возможность выразить нужное действие, а отчасти пото­му, что они обычно ведут к более компактным и эффективным программам, чем те, которые могут быть получены другими спо­собами.

Указатели и адреса

Так как указатель содержит адрес объекта, это дает воз­можность "косвенного" доступа к этому объекту через указа­тель. Предположим, что х - переменная, например, типа INT, а рх - указатель, созданный неким еще не указанным способом. Унарная операция & выдает адрес объекта, так что оператор

рх = &х; присваивает адрес х переменной рх; говорят, что рх "ука­зывает" на х. Операция & применима только к переменным и элементам массива, конструкции вида &(х-1) и &3 являются не­законными. Нельзя также получить адрес регистровой перемен­ной.

Унарная операция * рассматривает свой операнд как адрес конечной цели и обращается по этому адресу, чтобы извлечь содержимое. Следовательно, если Y тоже имеет тип INT, то

Y = *рх; присваивает Y содержимое того, на что указывает рх. Так пос­ледовательность

рх = &х;

Y = *рх;

присваивает Y то же самое значение, что и оператор

Y = X;

Переменные, участвующие во всем этом необходимо описать:

INT X, Y;

INT *PX;

Описание указателя

INT *PX;

говорит, что комбинация *PX имеет тип INT. Это означает, что если PX появляется в контексте *PX, то это эквивалентно переменной типа INT. Фактически синтаксис описания перемен­ной имитирует синтаксис выражений, в которых эта переменная может появляться. Это замечание полезно во всех случаях, связанных со сложными описаниями. Например,

DOUBLE ATOF(), *DP;

говорит, что ATOF() и *DP имеют в выражениях значения типа DOUBLE.

указатель может указывать только на определенный вид объектов.

Указатели могут входить в выражения. Например, если PX указывает на целое X, то *PX может появляться в любом кон­тексте, где может встретиться X. Так оператор

Y = *PX + 1

присваивает Y значение, на 1 большее значения X;

PRINTF("%D\N", *PX)

печатает текущее значение X;

D = SQRT((DOUBLE) *PX)

получает в D квадратный корень из X, причем до передачи фун­кции SQRT значение X преобразуется к типу DOUBLE. В выражениях вида

Y = *PX + 1

унарные операции * и & связаны со своим операндом более крепко, чем арифметические операции, так что такое выражение берет то значение, на которое указывает PX, прибавляет 1 и присваивает результат переменной Y.

Ссылки на указатели могут появляться и в левой части присваиваний. Если PX указывает на X, то

*PX = 0

полагает X равным нулю, а

*PX += 1

увеличивает его на единицу, как и выражение

(*PX)++

Круглые скобки в последнем примере необходимы; если их опус­тить, то поскольку унарные операции, подобные * и ++, выпол­няются справа налево, это выражение увеличит PX, а не ту пе­ременную, на которую он указывает.

И наконец, так как указатели являются переменными, то с ними можно обращаться, как и с остальными переменными. Если PY - другой указатель на переменную типа INT, то PY = PX копирует содержимое PX в PY, в результате чего PY указывает на то же, что и PX.

. Указатели и аргументы функций

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

SWAP(A, B);

определив функцию SWAP при этом следующим образом:

SWAP(X, Y) /* WRONG */

INT X, Y;

INT TEMP;

TEMP = X;

X = Y;

Y = TEMP; из-за вызова по значению SWAP не может воздействовать на аргументы A и B в вызывающей функции.

К счастью, все же имеется возможность получить желаемый эффект. Вызывающая программа передает указатели подлежащих изменению значений: SWAP(&A, &B); так как операция & выдает адрес переменной, то &A является указателем на A. В самой SWAP аргументы описываются как ука­затели и доступ к фактическим операндам осуществляется через них.

SWAP(PX, PY) /* INTERCHANGE *PX AND *PY */

INT *PX, *PY;

 

INT TEMP;

TEMP = *PX;

*PX = *PY;

*PY = TEMP;

 

Указатели в качестве аргументов обычно используются в функциях, которые должны возвращать более одного значения. (Можно сказать, что SWAP вOзвращает два значения, новые зна­чения ее аргументов). В качестве примера рассмотрим функцию GETINT, которая осуществляет преобразование поступающих в своболном формате данных, разделяя поток символов на целые значения, по одному целому за одно обращение. Функция GETINT должна возвращать либо найденное значение, либо признак кон­ца файла, если входные данные полностью исчерпаны. Эти зна­чения должны возвращаться как отдельные объекты, какое бы значение ни использовалось для EOF, даже если это значение вводимого целого.



Практическое задание:






Не нашли, что искали? Воспользуйтесь поиском:

vikidalka.ru - 2015-2024 год. Все права принадлежат их авторам! Нарушение авторских прав | Нарушение персональных данных