Справочник от Автор24
Поделись лекцией за скидку на Автор24

Работа со строками символов в Си. Строковые литералы

  • 👀 592 просмотра
  • 📌 529 загрузок
Выбери формат для чтения
Статья: Работа со строками символов в Си. Строковые литералы
Найди решение своей задачи среди 1 000 000 ответов
Загружаем конспект в формате doc
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Работа со строками символов в Си. Строковые литералы» doc
Лекция 2. Обработка символьной информации и документов сложной структуры. Файлы в СИ 2.1. Обработка символьной информации на Си 2.1.1. Символьный тип Описание символьной переменной а: char а; данные типа char занимают в памяти один байт и принимают значения на множестве символов, допутимых для данного компьютера. Внутренний код байта определяется по кодовой таблице. Тип сhar рассматривается в Си как тип целое; при желании над переменными типа char можно выполнять арифметические операции. Символьная константа записывается как соответствующий символ, заключенный в апострофы. Оператор а='а' означает, что символьной переменной с именем а присваивается значение символа а. Для использования управляющих символов в Си имеются управляющие константы, запись которых в апострофах начинается с наклонной черты (\), например: \n - перевод строки, \f - перевод страницы, \a - звонок, \0 - нулевой байт (используется для обозначения конца строки). Если в апострофах после косой черты стоит восьмеричная (начинается с 0 и содержит цифры от 0 до 7) или шестнадцатеричная (начинается с х или Х) константа, то она рассматривается как символ с соответствующим кодом; например, '\0100'-прописная латинская Р. 2.1.2. Работа со строками символов в Си. Строковые литералы.  В Си отсутствует специальный строковый тип. Вместо такого типа используется понятие строкового литерала. Строковый литерал - последовательность символов, заключенная в двойные кавычки, например, " text". В памяти ЭВМ строковый литерал представляется как массив элементов типа char, в конце которого помещен символ '\0' (нуль-терминатор). Адрес строкового литерала и интерпретация его как элемента языка зависит от приема его использования. Строковый литерал может использоваться в Си-программах следующим образом: 1. Для инициализации массивов типа char. Следующие описания являются идентичными: char str[6]="слово"; /*6-й символ - нуль-терминатор*/ char str[]="слово";/* 6 символов, последний – нуль-терминатор*/ char str[6]={'с','л','о','в','о', '\0'}; Если длина массива превышает длину литерала, то оставшиеся символы считаются неопределенными для локальных нестатических массивов или равными нулю для глобальных или локальных статистических массивов. Пример. void main() {char a[10]="слово"/*последние 4 символа имеют неопредел.знач.*/... В этом случае адрес первого символа литерала есть значение имени массива (адрес первого элемента массива). Массив располагается в стеке функций. 2. Для инициализации или присваивания значения переменной типа char *. Например: char *str1,*str2="text2";... str1="text1"; Литералы "text1" и "text2" располагаются в сегменте данных программы, значения адресов их первых элементов присваиваются переменным-указателям str1 и str2. Литералы в данном случае рассматриваются как указатели-константы. Замечание. Недопустимо присваивать значения, в том числе и значения литералов, именам массивов, так как имя массива - это указатель-константа. Например, следующий фрагмент программы неверен: char str[6]; str="слово";... 3. Для записи выводимого текста в функциях вывода (printf, puts, и т.д.). Литералы, используемые в этих операторах, хранятся в сегменте данных. 4. Последовательности символов, вводимые с помощью функции scanf по форматам s или с помощью функции gets и аналогичных функций, записываются в память как литералы (символ \n не заносится в память, вместо него записывается \0). Адресом литерала становится адрес переменной-указателя или имя символьного массива, в который вводится литерал. Для ввода и вывода строк в Си можно применять функции scanf и printf с использованием формата s. Существуют также функции ввода и вывода строк символов puts и gets. Они действуют так же, как scanf("%s",string) и printf("%s\n",string), за одним исключением: scanf принимает символы, пока не встретится \n, а передает в память символы до \n или пробела (символы от первого пробела до \n остаются в буфере); gets передает в память все символы до \n. 2.1.3. ПРИМЕРЫ обработки строк Пример 1. Вычислить количество слов в строке; под словом понимается группа символов, не содержащая пробелов. Слова могут разделяться одним или несколькими пробелами В приведенной программе мы подсчитываем число "концов слов", т. е. число пар символов "непробел-пробел" или "непробел-ко­нец строки". Алгоритм (блок-схема на рис.11) предусматривает последовательный просмотр символов строки от ее начала, цикл заканчивается на символе '\0'. #include #include #define NMAX 81 /*максимальная длина стpоки*/ void main() {char pr[NMAX];/*рассматриваемая строка*/ int k,n,i; /*k-число слов, n-длина стpоки, i-счетчик символов*/ puts(" Введите стpоkу"); gets(pr); k=0; i=0; while (pr[i]!='\0') {if ((pr[i]!=' ') && ((pr[i+1]==' ') || (pr[i+1]=='\0'))) k=k+1; i=i+1; }; printf(" Число слов pавно %2d\n",k); getch(); } Пример 2. Определить, сколько в последовательности А малых латинских букв и сколько в последовательности В цифр. Пояснения к примеру 2. Известно, что во всех широко используемых в настоящее время кодовых таблицах символов малые латинские буквы от ‘a’ до ‘z’ расположены друг за другом в порядке возрастания кода. Цифры от ‘0’ до ‘9’ – также расположены подряд. Поэтому надо найти, сколько символов строки А удовлетворяют условию: ‘a’ ≤ A[i] ≤ ‘z’, и сколько символов строки B удовлетворяют условию: ‘0’ ≤ B[i] ≤ ‘9’. Так как алгоритмы обработки A и B отличаются только обозначениями и константами, то следует разработать общую функцию обработки, которая должна вычислять количество символов некоторой строки str, расположенных в интервале от с1 до с2. Прототип такой функции Си: int number(char *str, char c1, char c2); ниже приведена программа, выполняющая задание: #include #include #define NMAX 81 /*максимальная длина стpоки*/ int number(char *str, char c1, char c2); void main() {char a[NMAX], b[NMAX];/*заданные строки*/ puts("Input a"); gets_s(a); puts("Input b"); gets_s(b); printf(" ka=%d\n",number(a,'a','z')); printf(" kb=%d\n",number(b,'0','9')); _getch(); } int number(char *str, char c1,char c2) { int i, k; k=0; i=0; while (str[i]!='\0') { if ((str[i]>=c1)&&(str[i]<=c2)) k=k+1; i=i+1; } return(k); } 2.1.4. Функции и макросы для работы с символьной информацией Макросы для проверки вида символов и преобразования символов содержатся в заголовочном файле . Примеры обращений к макросам: isalnum(c) - истина ,если с - буква или цифра; isalfa(c) - истина, если с - буква; isascii(c) - истина, если код символа с меньше или равен 127; tolower(c) - преобразует символ прописной буквы в символ строчной, не изменяя остальные символы; не являющиеся прописными буквами символы не преобразуются; toupper(c) - преобразует символ строчной буквы в символ прописной (обратная для tolower). Эти макросы не предназначены для работы с русскими буквами. Библиотека для работы со строками символов содержит, например, функции: определение длины строки, копирование строк, выделение подстрок, определение вхождения символа или подстроки в строку, сравнение строк, конкатенация (сцепление строк), вывод строк с сообщениями об ошибках и т. д. Прототипы функций содержатся в заголовочном файле . Большинство функций обрабатывают только последовательности символов, заканчивающиеся нуль-терминатором. В примерах программ следующей лекции использованы функции: • strlen(const char *s) - возвращает длину в байтах для строки, на которую указывает s, не учитывая нуль-терминатор; • strcpy(char *s1, const char *s2) - копирует строку, на которую указывает s2, в строку, на которую указывает s1; • strcmp(const char s1, const char* s2) - выполняет сравнение строк, на которые указывают s1 и s2; возвращает 0, если строки одинаковы, и положительное значение, если s1>s2, иначе отрицательное; • strncpy(char *s1, const char *s2, int n) - копирует не более n первых символов строки, на которую указывает s2, в строку, на которую указывает s1; если n меньше длины строки s2, то в s1 не переносится символ '\0'; • strcat(char* str1, const char* str2) – присоединяет к строке str1 строку str2; под str1 должна быть отведена память, достаточная для хранения результата; • strstr(const char *s1,const char *s2) - возвращает указатель на место первого вхождения s2 в s1. При работе с символьной информацией часто требуются функции, преобразующие строку символов в число и числа в строку символов (иначе говоря, внешнее представление числа во внутреннее и наоборот). Прототипы таких функций содержатся в заголовочном файле , некоторые из них дублируются в и других заголовочных файлах. В примерах следующей лекции будет использоваться функция atof, преобразующая строку символов в значение типа double; ее шаблон: double atof (const char *s) Все вышеупомянутые функции, в частности, используются при программировании обработки таблиц. В таких задачах часто требуется: • выделить смысловые поля таблицы, т. е. подстроки, с помощью функций strcpy, strncpy; • преобразовать некоторые поля из символьного представления в числовое (с помощью функций atof, atoi и др.); • проанализтровать символьные поля с помощью функции strstr, strcmp; • подготовить строки выходных данных с помощью, например, itoa, gcvt (см. справочную литературу) и strcat. Программирование обработки табличных данных может также выполняться с использованием структур, которые рассматриваются в следующем параграфе. 2.2. Тип "структура" в Си Пока мы рассматривали один вид сложных (занимающих несколько ячеек памяти) данных — массив; одним из основных свойств массива является однотипность его компонент. Многие информационно-логические задачи связаны с обработкой документов, содержащих в себе информация разного типа (числовую, символьную и т. д.) Примеры таких документов: пла­тежные ведомости (фамилии и имена - символьная информация, де­нежные суммы - числовая), карточки больных в поликлинике, библио­течная информация. Для программирования алгоритмов обработки такой информации необходимо иметь сложный тип, объединяющий разнотипные компоненты. Таким типом является структура в Си. Структурная переменная, или просто структура, состоит из не­скольких данных (называемых полями), возможно, разного типа. Структура тип "структура" (шаблон) переменная типа "структура" Описание шаблона: Описание структурной переменной typedef struct { Тип1 Список1ИменПолей; ИмяШаблона ИмяПеременной Тип2 Список2ИменПолей; . . .  ключевое struct слово не нужно при ТипN СписокNИменПолей; использовании typedef }  ИмяШаблона или struct  ИмяШаблона struct  ИмяШаблона ИмяПеременной { Тип1 Список1ИменПолей;¦ Тип2 Список2ИменПолей; . . .  ТипN СписокNИменПолей; } ; Пример. Характеристики книги: автор (author), название (title), год издания (year), цена (price), описываются шаблоном BOOK. typedef struct {char author[20]; char title[44];/*описание*/ int year; float price} BOOK; /*шаблона BOOK*/ /*или можно описать тот же самый шаблон так: struct BOOK {char author[20]; char title[44]; int year; float price} ;*/ BOOK b;/*описание структурной переменной b*/ Память, занимаемая структурой, равна сумме объемов памяти полей (если исключить из рассмотрения особенности, связанные с выравниванием). В любом случае для определения размера памяти структуры можно использовать операцию sizeof(). Шаблон ВООК, на­пример, описывает структуру размером памяти 70. Обращение к полю структурной переменной: ИмяСтруктуры.ИмяПоля или АдресСтруктуры->ИмяПоля .(точка) и -> являются операциями, соответственно, прямого и косвенного выбора компоненты структурированной переменной. Например, struct BOOK a,*pnta=&a;... a.author="Byron"; pnta->author="Byron"; /*эквивалентные опера­торы*/ Примеры программ с использованием структур рассмотрим после того, как нучимся работать с файлами, так как такие программы обычно связаны с обработкой больших объемов данных. В современном программировании структуры, прежде всего, нужны для объединения компонентов разного типа в одну переменную в соответствии с логикой задачи; тем самым, примение структур улучшает восприятие программы. В Си существует еще один сложный тип, описание которого формально похоже на структуру. Это тип (и переменная) объедине­ние. Объединение - это переменная, содержащая поля разного типа, помещаемые в одно и то же место памяти. По существу объедине­ние дает способ различной интерпретация содержимого памяти. Описание шаблона (типа) объединения и переменной этого типа выполняется также, как для структуры, только вместо ключевого слова struct используется union. Размер памяти, занимаемой объе­динением, равен максимальному из размеров полей. 2.3.Файлы в Си 2.3.1. Общее понятие о файлах в программировании Термин файл используется в программировании в двух смыс­лах. В рамках операционной системы файл понимается как область памяти внешнего запоминающего устройства (обычно диска), имеющая имя. В алгоритмических языках файл - это тип данных, используемый, как правило, при работе с внешними запоминающими устройствами. В Си нет специального типа файл, но есть предопределенный струк­турный тип FILE, описание которого содержится в заголовочном файле stdio.h. Файл - это последовательность однотипных компонент. Число компонент файла не ограничено. Компонентой файла мо­жет быть строка или байт, или значение какого-либо типа (целого, вещественного, структура, и т. д.). После последней компоненты файла стоит специальный код, называемый признаком конца файла; этот код обычно ставится автоматически, без участия программиста. В классическом понимании файл рассматривается как абст­рактное обобщение данных на устройстве с последовательным дос­тупом, типичным представителем которого является магнитная лента. В библиотеках современных языков программирования, ко­нечно, имеются средства и для работы с файлами прямого доступа. Абстрактная последовательность данных на некотором внешнем устройстве также называется потоком. Обычно в алгоритмических языках определяется программное и физическое имя файлов. Программное имя - это имя переменной типа файл (в СИ типа FILE*), физическое имя - это имя файла на внешнем запоминающем устройстве. Существуют специальные операторы, связывающие про­граммное и физическое имя файла (см.§2.3.2). Файлы бывают текстовыми и двоичными. Текстовые файлы хранят информацию во внешнем пред­ставлении. Они имеют два основных признака: во-первых, их ком­понентами являются строки символов; во-вторых, эта символьная информация при чтении из файла или записи в файл преобразуется в соответствии с типом вводимых или выводимых переменных. Эти файлы являются обобщением данных на устройстве консоль (CON). Умение работать с текстовыми файлами необхо­димо даже начинающим программистам, так как обычно имеется потребность в длительном хранении исходных и выходных данных. Текстовые файлы можно ввести в ЭВМ, прочитать, исправить с помощью текстового редактора. Они хранят информацию во внеш­нем представлении, в виде, понятном для человека. Такие файлы часто называются видимыми. Двоичный файл - это последовательность байтов; обмен ин­формации между двоичным файлом и данными программы про­исходит без преобразования. 2.3.2. Функции Си для работы с файлами Шаблон структуры FILE и прототипы основных функций работы с файлами хранятся в stdio.h. Перед использованием файла необхо­димо: 1. Описать его программное имя как указатель на структуру типа FILE: FILE *ИмяУказателя 2. Открыть файл. Функция открытия файла устанавливает связь между программным и физическим именами файла и подго­тавливает его к использованию. Шаблон функции открытия файла: FILE *fopen(char *ИмяФайла, char *режим); первый параметр задает строку, в которой хранится физиче­ское имя файла, записанное по правилам операционной системы, второй - режим открытия. Приведем некоторые режимы: “r” - открыть для чтения; “w” - открыть для записи; “rb” - открыть двоичный файл для чтения; “wb” - открыть двоичный файл для записи; “rt” - открыть текстовый файл для чтения; “wt” - открыть текстовый файл для записи; “a” – открыть файл для дополнения. Результат функции fopen необходимо присвоить переменной типа FILE *. Если функции fopen удалось открыть указанный файл, возвращается указатель на FILE. Если же файл не может быть открыт, возвращается NULL. Пример открытия файла и обнаружения ошибки при открытии: FILE *fp; fp=fopen(“x.txt”,”w”); if (fp==NULL) puts(“Ошибка при открытии файла”) else .... Или: FILE *fp; if ((fp=fopen(“x.txt”,”w”))==NULL) { puts(“Ошибка при открытии файла”); exit(1); }. Функция с шаблоном int feof(FILE *fp); возвращает значение, не равное 0 (истина), если (при открытии файла, или чтении из файла, или записи в файл) конец файла достигнут, и значение 0 (ложь) в противном слу­чае. В стандартной библиотеке Си функции ввода-вывода, в частности доступа к файлам, могут возвращать значение, равное символьной константе (точнее макроопределению) EOF для индикации, что достигнут конец файла. Реальное значение EOF является отрицательным числом, зависящим от системы (в основном −1), что гарантирует несовпадение с кодом символа. Далее поясним, что такое открытие файла для чтения, записи и дополнения. Открытие файла для чтения предусматривает выполнение следующих действий: 1. Поиск файла с заданным физическим именем; если файл не найден, то выводится сообщение об ошибке. 2. Указатель файла устанавливается на первую компоненту. 3. Компонента, на которой стоит указатель, считывается в буфер. 4. Если считан признак конца файла, то функция feof устанавливается в значение истина, иначе – в значение ложь. Открытие файла для записи предусматривает выполнение следующих действий: 1. Поиск файла с заданным физическим именем; если файл не найден, то создается новый файл. 2. Содержимое файла очищается. 3. Указатель файла устанавливается на конец файла, который, поскольку файл очищен, одновременно является его началом. 4. Функция feof устанавливается в значение истина. Это значение сохраняется при последующей записи в файл, т. е. запись происходит в конец файла. Открытие файла для дополненния предусматривает выполнение следующих действий: 1. Поиск файла с заданным физическим именем; если файл не найден, то выдается сообщение об ошибке. 2. Указатель файла устанавливается на конец файла (после последней компоненты). 3. Функция feof устанавливается в значение истина. Рассмотренные ранее функции scanf, printf, puts, gets имеют аналоги для работы с текстовыми файлами. Их названия получа­ются добавлением справа буквы f к именам упомянутых функций. Шаблоны функций файлового форматного вывода и ввода: int fprintf(програм_имя_ файла, форматная_строка, список_вывода); int fscanf(програм_имя_ файла, форматная_строка, список_вывода); Шаблоны функций fputs и fgets: char *fgets(char *string, int nmax,FILE *f) char *fputs(char *string, FILE *f) где string - адрес начала вводимого массива символов, f - указатель на текстовый файл, nmax - максимальная длина вводимой строки плюс 1. Функции putc (записать символ в поток) и getc (прочитать сим­вол из потока) работают как с текстовыми, так и с двоичными фай­лами. Их шаблоны: int putc(int ch, FILE* f) (если оператор выполнен успешно, то возвращается записанный символ, иначе EOF) int getc(FILE *f) (если считывание не выполнено, то EOF) Для работы с двоичными файлами предназначены функции чтения и записи блоков: unsigned fread(void *buf, int zap, int n,FILE *f) unsigned fwrite(const void *buf, int zap, int n,FILE *f) где buf - указатель на область памяти, с которой будет происхо­дить обмен информацией, zap – размер в байтах считываемого или записываемого элемента (записи), n – максимальное число считываемых (записываемых) элементов, f - указатель на файл. Функция fread (fwrite) возвращает количество прочитанных (записанных) записей, которое стандартно равно n, но может быть меньше n при возникновении ошибки или достижении конца файла до считывания n записей. После окончания работы с файлом его необходимо закрыть. При закрытии файла выполняется его сохранение (естественно, с перерегистрацией в каталоге). Кроме того, связь между программным и физическим именем файла, установленная при открытии файла, разрушается. Шаблон функции за­крытия файла: int fclose(FILE * f) - возвращает значение нуль, если операция закрытия прошла успешно. 2.3.3. Примеры программ, использующих файлы Пример 1. Размеры матрицы n и m и значения элементов матрицы считываются из текстового файла f_in.txt , затем матрица изменяется (скажите, как) и выводится в текстовый файл f_out.txt. #include #include void main() { float a[5][5]; int n,m,i,j; FILE* f_in, *f_out; f_in=fopen("f_in.txt","rt"); //"c:\\dir\\f_in.txt" fscanf(f_in,"%d%d", &n,&m); for (i=0;i #include #include #define NMAX 100 void main() { char s[NMAX]; int k,i;//k-число Ивановых FILE *f_in, *f_out; f_in=fopen("f_in.txt", "rt"); if (f_in==NULL) puts("file is not opened"); else if feof(f_in) puts("file is empty"); else { f_out=fopen("f_out.txt", "wt"); k=0; while (fgets(s,NMAX+1,f_in)!=NULL) { if (strstr(s,"Иванов ")!=NULL || strstr(s,"Иванова ")!=NULL) { k=k+1; fputs(s,f_out); } } if (k>0) { fclose(f_out); printf ("k=%d\n", k); puts("output file is ready"); } else puts("k=0"); } _getch(); } Пример 3. Та же задача, что и в примере 2, но каждая строка текстового файла считывается в переменную-структуру. #include #include #include #pragma hdrstop #define NMAX 100 void main() { typedef struct { char s1[NMAX],s2[NMAX]; } fam_im; fam_im f_i; int k,i;//число Ивановых FILE *f_in, *f_out; f_in=fopen("f_in.txt", "rt"); if (f_in==NULL) puts("file is not opened"); else if feof(f_in) puts("file is empty"); else { f_out=fopen("f_out.txt", "wt"); k=0; while (fscanf(f_in,"%s %s",&f_i.s1,&f_i.s2)!=EOF) { if (strcmp(f_i.s1,"Иванов")==0|| strcmp(f_i.s1,"Иванова")==0) { k=k+1; fprintf(f_out, "%s %s\n", f_i.s1,f_i.s2); } } if (k>0) { fclose(f_out); printf ("k=%d\n", k); puts("output file is ready"); } else puts("k=0"); } _getch(); }
«Работа со строками символов в Си. Строковые литералы» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Найди решение своей задачи среди 1 000 000 ответов
Найти
Найди решение своей задачи среди 1 000 000 ответов
Крупнейшая русскоязычная библиотека студенческих решенных задач

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot