В следующем фрагменте кода строка Hello копируется в строку str. char str[81];
strcpy(str, "Hello");
Типичной ошибкой при работе с функцией strcpy() является передача ей неправильного указателя на строку str_in. Например, некорректным
оказывается следующий фрагмент кода: void foo()
{ |
char str1[25] = “Hello”; |
|
|
char* str2; |
|
|
strcpy(str1, str2); |
*/ |
} |
/* другой код |
|
|
|
|
Ошибка |
в приведенном выше коде состоит в отсутствии |
|
инициализации |
указателя str2. |
|
Для целей объединения строк можно использовать две функции: strcat() и strncat(). Вторая из этих функций (strncat()) в отличие от первой ограничивает количество символов, добавляемых в память, в которой происходит объединение строк.
Объявления рассматриваемых функций имеют следующий вид:
#include<string.h>
char* strcat(char* out_str, const char* in_str); char* strncat(char* out_str, const char* in_str,
size_t n);
Функция strcat() присоединяет содержимое строки in_str к строке out_str. Параметр in_str должен указывать на строку, которая заканчивается нуль - символом. Конечный “нуль – символ”, первоначально завершающий строку out_str, перезаписывается первым символом строки in_str. Функция strcat() возвращает значение указателя out_str. Если массивы in_str и out_str перекрываются поведение функции strcat() не определено.
В следующей программе две строки читаются с клавиатуры, затем
объединенная строка выводится на экран дисплея.
#include<stdio.h>
#include<string.h> int main(void)
{ char buf1[64], buf2[64]; gets(buf1);
gets(buf2); strcat(buf1, buf2);
printf(buf1); return 0;
}
Перейдем к рассмотрению функции strncat(). Эта функция присоединяет не более n символов строки in_str в конец строки out_str. Если “нуль –
116
символ” строки in_str достигнут раньше, чем будут прочитаны n символов строки in_str, то этот символ копируется, и процесс присоединения заканчивается. Если среди скопированных n символов не встретился нуль – символ, то он добавляется в строку in_str и процесс присоединения на этом заканчивается. В этом случае в выходную строку записывается n + 1 символ. Если в вызове функции n или отрицательно, то функция не изменяет выходную строку out_str.
Объявление этой функции имеет следующий вид
#include<string.h>
int strcmp(const char* in_str1, const char* in_str2);
Функция strcmp() выполняет так называемое лексографическое сравнение строк. Функция возвращает нулевое значение, если строки совпадают. Функция возвращает положительное значение, если строка in_str1 > in_str2. Наконец, функция возвращает отрицательное значение, если in_str1 < in_str2. Строка in_str1 считается больше строки in_str2, если первый несовпадающий ее символ имеет код, превышающий код соответствующего ему символа строки in_str2.
Ниже приводится пример применения функции strcmp().
#include<stdio.h>
#include<string.h>
int main(void) |
|
|
|
{ |
|
|
|
char name[32] = "Tom"; |
|
|
|
/* Выводится положительное число */ |
/* |
||
printf("%d\n", strcmp(name, "Alic"); |
|||
/* Выводится отрицательное число */ |
|
||
printf("%d\n", strcmp(name, "Victor"); |
|
||
/* |
Выводится нуль |
*/ |
|
printf("%d\n", strcmp(name, "Tom"); |
|
||
return |
0; |
|
|
}
Ограничимся рассмотрением массива строк, построенного на основе двумерного символьного массива с фиксированными размерами. Правила работы с массивом строк рассмотрим на простом примере.
Постановка задачи. Необходимо ввести с клавиатуры “n” строк(n <= 20), длина которых не превышает 80 символов. Вводимые строки записать в строковый массив. После завершения ввода выполнить вывод строк, сохраненных в массиве. Ввод и вывод организовать с помощью функций пользователя.
117
Решение.
//File main.c #include <stdio.h> #include "Strings.h"
//File main.c #include <stdio.h> #include "Strings.h" int main(void)
{
char strs[MSTRS][MLEN + 1]; int n;
printf("n="); scanf("%d%*c", &n);
input_arr_strs(strs, n); printf("\n\n"); output_arr_strs(strs, n); return 0;
}
// File Strings.h
#ifndef STRINGS_H_INCLUDED #define STRINGS_H_INCLUDED #define MSTRS 20
#define MLEN 80
void input_arr_strs(char ar[][MLEN + 1], int n);
void output_arr_strs(const char ar[][MLEN + 1], int n);
#endif // STRINGS_H_INCLUDED
// File Strings.c #include "Strings.h" #include <stdio.h>
void input_arr_strs(char ar[][MLEN + 1], int n)
{
for(int i = 0; i < n; i++)
{
printf("#%d->", i + 1); gets(ar[i]);
}
}
void output_arr_strs(const char ar[][MLEN + 1], int n)
{
printf("%5s\t%-50s\n", "I", "STS"); for(int i = 0; i < n; i++)
{
printf("%5d\t%-50s\n", i + 1, ar[i]);
}
}
118
Структура – это вторая разновидность агрегатных типов данных языка Си. Структура – совокупность величин, объединенных одним именем. Компоненты структуры называют:
∙элементами,
∙полями,
∙членами.
От уже рассмотренных выше массивов структура отличается в следующих отношениях:
∙отсутствует упорядоченность между компонентами,
∙в отличие от массивов компоненты структуры могут иметь разный тип.
∙другой способ обращения к компонентам; к компонентам
структуры следует обращаться по имени их полей (а не индексу как это имеет место в случае массивов).
Обратим внимание на неоднозначность термина структура. В языке Си под этим термином наряду со структурой как типом данных понимают переменную, имеющую тип структуры.
Общий формат, позволяющий наряду с типом объявлять и переменные, имеет следующий вид:
struct[<α>]
{
<β> }[γ];
119
Здесь:
∙struct – ключевое слово языка Си,
∙α - необязательный элемент, называемый тегом,
∙ |
β |
- список объявлений полей, |
∙ |
γ |
- список переменных, имеющих тип объявляемой структуры. |
Элементы объявления α и γ могут отсутствовать. Список γ подчиняется синтаксису обычных переменных. Переменные, включенные в этот список, могут использоваться только в составе структурной переменной. Определение такого формата выполняют две функции:
∙объявляют структуру как тип данных.
∙определяет переменные, имеющие этот тип. Рассмотрим ряд примеров.
Пример 1. Совместное определение типа и переменных
#define MLEN 81 struct person_salary
{
char fio[MLEN]; double salary;
} employee, worker;
Тегом определяющей здесь структуры является здесь идентификатор person_salary. Структура имеет два поля. Первым полем является строка fio, предназначенная для хранения фамилии, имени и отчества. Второе поле имеет тип double и предназначено для хранения сведений о заработке. Здесь же определены две переменные, имеющие структурный тип:
∙employee (служащий),
∙worker (рабочий).
Здесь необходимо следует иметь в виду следующее. В программе, написанной на языке C++, тег является именем типа. В языке Си в качестве имени типа следует использовать конструкцию struct <α (тег)> .
Пример 2. Раздельное определение типа и переменных
#define MLEN 81 struct person_salary
{
char fio[MLEN]; double salary;
};
//…
struct person_salary employee, worker;
Пример 3. Компонент тег можно опускать
#define MLEN 81 struct
{
char fio[MLEN]; double salary;
} employee, worker;
120