ТОР 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]; В первом случае просто описывается символьный массив из десяти элементов. Надо иметь в виду, что если мы собираемся использовать его как строку, то реально мы сможем использовать лишь девять символов, а еще один нам понадобится для "нулевого" символа, ограничивающего строку. Во втором случае описывается символьный массив из десяти элементов (т.е. в памяти выделяется 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 от вызова к вызову может варьироваться.
Функции mem предназначены для манипулирования с объектами как с массивами символов, их назначение - получить интерфейсы к эффективным программам. В таблице s и t имеют тип void*, Cs и ct-const void*. n-size_t,c-int приведенное к char
Задание на строки: 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, даже если это значение вводимого целого. Практическое задание: Не нашли, что искали? Воспользуйтесь поиском:
|