- •Int a; /* целая
- •Int n; // Переменная n целого типа double a; // Переменная a вещественного типа двойной точности
- •Вещественные константы
- •Символьные константы
- •Строковые константы
- •Логические операции
- •Тернарные операции
- •Оператор ветвления switch
- •Параметрический цикл for
- •Тип *имя_объекта;
- •Стандартные функции динамического выделения памяти
- •Динамическое выделение памяти для одномерных массивов
- •Основные функции стандартной библиотеки string.H
- •Массивы структур
- •Идентификатор(аргумент1, ..., агрументn)
- •Функция, позволяющая вывести день недели на русском языке
- •Файловая структура fat32
- •Работа с файлами в языке Си
Стандартные функции динамического выделения памяти
Функции динамического выделения памяти находят в оперативной памяти непрерывный участок требуемой длины и возвращают начальный адрес этого участка.
Функции динамического распределения памяти:
void* malloc(РазмерМассиваВБайтах); void* calloc(ЧислоЭлементов, РазмерЭлементаВБайтах);
Для использования функций динамического распределения памяти необходимо подключение библиотеки <malloc.h>:
#include <malloc.h>
Поскольку обе представленные функции в качестве возвращаемого значения имеют указатель на пустой тип void, требуется явное приведение типа возвращаемого значения.
Для определения размера массива в байтах, используемого в качестве аргумента функции malloc() требуется количество элементов умножить на размер одного элемента. Поскольку элементами массива могут быть как данные простых типов, так и составных типов (например, структуры), для точного определения размера элемента в общем случае рекомендуется использование функции.
int sizeof(тип);
которая определяет количество байт, занимаемое элементом указанного типа.
Память, динамически выделенная с использованием функций calloc(), malloc(), может быть освобождена с использованием функции
free(указатель);
"Правилом хорошего тона" в программировании является освобождение динамически выделенной памяти в случае отсутствия ее дальнейшего использования. Однако если динамически выделенная память не освобождается явным образом, она будет освобождена по завершении выполнения программы.
Динамическое выделение памяти для одномерных массивов
Форма обращения к элементам массива с помощью указателей имеет следующий вид:
int a[10], *p; // описываем статический массив и указатель int b; p = a; // присваиваем указателю начальный адрес массива ... // ввод элементов массива b = *p; // b = a[0]; b = *(p+i) // b = a[i];
Пример: Организация динамического одномерного массива и ввод его элементов.
#include <stdio.h> #include <malloc.h> #include <stdlib.h> int main() {
int *a; // указатель на массив
int i, n;
system("chcp 1251");
system("cls");
printf("Введите размер массива: ");
scanf("%d", &n);
// Выделение памяти
a = (int*) malloc(n*sizeof(int));
// Ввод элементов массива
for(i=0; i<n; i++)
{
printf("a[%d] = ", i);
scanf("%d", &a[i]);
}
// Вывод элементов массива
for(i=0; i<n; i++)
printf("%d ", a[i]);
free(a);
getchar(); getchar();
return 0; }
Результат
выполнения программы:
Динамическое выделение памяти для двумерных массивов
Пусть требуется разместить в динамической памяти матрицу, содержащую n строк и m столбцов. Двумерная матрица будет располагаться в оперативной памяти в форме ленты, состоящей из элементов строк. При этом индекс любого элемента двумерной матрицы можно получить по формуле
index = i*m+j;
где i - номер текущей строки; j - номер текущего столбца.
Рассмотрим матрицу 3x4 (см. рис.)
Индекс выделенного элемента определится как
index = 1*4+2=6
Объем памяти, требуемый для размещения двумерного массива, определится как
n·m·(размер элемента)
Однако поскольку при таком объявлении компилятору явно не указывается количество элементов в строке и столбце двумерного массива, традиционное обращение к элементу путем указания индекса строки и индекса столбца является некорректным:
a[i][j] - некорректно.
Правильное обращение к элементу с использованием указателя будет выглядеть как
*(p+i*m+j),
где p - указатель на массив, m - количество столбцов, i - индекс строки, j - индекс столбца.
Пример Ввод и вывод значений динамического двумерного массива
#include <stdio.h> #include <malloc.h> #include <stdlib.h> int main() {
int *a; // указатель на массив
int i, j, n, m;
system("chcp 1251");
system("cls");
printf("Введите количество строк: ");
scanf("%d", &n);
printf("Введите количество столбцов: ");
scanf("%d", &m);
// Выделение памяти
a = (int*) malloc(n*m*sizeof(int));
// Ввод элементов массива
for(i=0; i<n; i++) // цикл по строкам
{
for(j=0; j<m; j++) // цикл по столбцам
{
printf("a[%d][%d] = ", i, j);
scanf("%d", (a+i*m+j));
}
}
// Вывод элементов массива
for(i=0; i<n; i++) // цикл по строкам
{
for(j=0; j<m; j++) // цикл по столбцам
{
printf("%5d ", *(a+i*m+j)); // 5 знакомест под элемент массива
}
printf("\n");
}
free(a);
getchar(); getchar();
return 0; }
Результат
выполнения
Возможен также другой способ динамического выделения памяти под двумерный массив - с использованием массива указателей. Для этого необходимо:
выделить блок оперативной памяти под массив указателей;
выделить блоки оперативной памяти под одномерные массивы, представляющие собой строки искомой матрицы;
записать адреса строк в массив указателей.
Графически
такой способ выделения памяти можно
представить следующим образом.
При
таком способе выделения памяти компилятору
явно указано количество строк и количество
столбцов в массиве.
Пример
#include <stdio.h> #include <malloc.h> #include <stdlib.h> int main() {
int **a; // указатель на указатель на строку
int i, j, n, m;
system("chcp 1251");
system("cls");
printf("Введите количество строк: ");
scanf("%d", &n);
printf("Введите количество столбцов: ");
scanf("%d", &m);
// Выделение памяти под указатели на строки
a = (int**)malloc(n*sizeof(int*));
// Ввод элементов массива
for(i=0; i<n; i++) // цикл по строкам
{
// Выделение памяти под хранение строк
a[i] = (int*)malloc(m*sizeof(int));
for(j=0; j<m; j++) // цикл по столбцам
{
printf("a[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
}
// Вывод элементов массива
for(i=0; i<n; i++) // цикл по строкам
{
for(j=0; j<m; j++) // цикл по столбцам
{
printf("%5d ", a[i][j]); // 5 знакомест под элемент массива
}
printf("\n");
free(a[i]); // освобождение памяти под строку
}
free(a);
getchar(); getchar();
return 0; }
Результат выполнения программы аналогичен предыдущему случаю.
С помощью динамического выделения памяти под указатели строк можно размещать свободные массивы. Свободным называется двухмерный массив (матрица), размер строк которого может быть различным. Преимущество использования свободного массива заключается в том, что не требуется отводить память компьютера с запасом для размещения строки максимально возможной длины. Фактически свободный массив представляет собой одномерный массив указателей на одномерные массивы данных.
Для размещения в оперативной памяти матрицы со строками разной длины необходимо ввести дополнительный массив m, в котором будут храниться размеры строк.
Пример
#include <stdio.h> #include <stdlib.h> int main() {
int **a;
int i,j, n,*m;
system("chcp 1251");
system("cls");
printf("Введите количество строк: ");
scanf("%d", &n);
a = (int**)malloc(n*sizeof(int*));
m = (int*)malloc(n*sizeof(int)); // массив кол-ва элементов строк
// Ввод элементов массива
for(i = 0; i<n; i++) {
printf("Введите количество столбцов строки %d: ", i);
scanf("%d", &m[i]);
a[i] = (int*)malloc(m[i]*sizeof(int));
for(j = 0; j<m[i]; j++) {
printf("a[%d][%d]= ", i, j);
scanf("%d", &a[i][j]);
}
}
// Вывод элементов массива
for(i = 0; i<n; i++) {
for(j = 0; j<m[i]; j++) {
printf("%3d ",a[i][j]);
}
printf("\n");
}
getchar(); getchar();
return 0; }
Результат
выполнения
Функции обработки строк в Cи
Главная > Язык Си > Функции обработки строк в Cи
В программе строки могут определяться следующим образом:
как строковые константы;
как массивы символов;
через указатель на символьный тип;
как массивы строк.
Кроме того, должно быть предусмотрено выделение памяти для хранения строки.
Любая последовательность символов, заключенная в двойные кавычки "", рассматривается как строковая константа. Для корректного вывода любая строка должна заканчиваться нуль-символом '\0'=0. При объявлении строковой константы нуль-символ добавляется к ней автоматически. Так, последовательность символов, представляющая собой строковую константу, будет размещена в оперативной памяти компьютера, включая нулевой байт.
Под хранение строки выделяются последовательно идущие ячейки оперативной памяти. Таким образом, строка представляет собой массив символов. Для хранения кода каждого символа строки отводится 1 байт.
Для помещения в строковую константу некоторых служебных символов используются символьные комбинации. Так, если необходимо включить в строку символ двойной кавычки, ему должен предшествовать символ "обратный слеш": '\"'. Строковые константы размещаются в статической памяти. Начальный адрес последовательности символов в двойных кавычках трактуется как адрес строки. Строковые константы часто используются для осуществления диалога с пользователем в таких функциях, как printf().
При определении массива символов необходимо сообщить компилятору требуемый размер памяти.
char m[82];
Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой:
char m2[]="Горные вершины спят во тьме ночной."; char m3[]={'Т','и','х','и','е',' ','д','о','л','и','н','ы',' ','п','о','л','н','ы',' ','с','в','е','ж','е','й',' ','м','г','л','о','й','\0'};
В этом случае имена m2 и m3 являются указателями на первые элементы массивов:
m2 эквивалентно &m2[0] m2[0] эквивалентно 'Г' m2[1] эквивалентно 'o' m3 эквивалентно &m3[0] m3[2] эквивалентно 'x'
При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы:
char m2[80]="Горные вершины спят во тьме ночной.";
Для задания строки можно использовать указатель на символьный тип.
char *m4;
В этом случае объявление массива переменной m4 может быть присвоен адрес массива:
m4 = m3; *m4 эквивалентно m3[0]='Т' *(m4+1) эквивалентно m3[1]='и'
Следует отметить, что m3 является константой-указателем. Нельзя изменить m3, так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4.
Для указателя можно использовать операцию увеличения (перемещения на следующий символ):
m4++;
Иногда в программах возникает необходимость описание массива символьных строк. В этом случае можно использовать индекс строки для доступа к нескольким разным строкам.
char *poet[4] = {"Погиб поэт!", "- невольник чести -", "Пал," , "оклеветанный молвой..."};
В этом случае poet является массивом, состоящим из четырех указателей на символьные строки. Каждая строка символов представляет собой символьный массив, поэтому имеется четыре указателя на массивы. Указатель poet[0] ссылается на первую строк:
*poet[0] эквивалентно 'П', *poet[l] эквивалентно '-',
Инициализация выполняется по правилам, определенным для массивов. Тексты в кавычках эквивалентны инициализации каждой строки в массиве. Запятая разделяет соседние последовательности. Кроме того, можно явно задавать размер строк символов, используя описание, подобное такому:
char poet[4][23];
Разница заключается в том, что такая форма задает «прямоугольный» массив, в котором все строки имеют одинаковую длину.
Описание
сhar *poet[4];
определяет свободный массив, где длина каждой строки определяется тем указателем, который эту строку инициализирует. Свободный массив не тратит память напрасно.
Большинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:
выделить блок оперативной памяти под массив;
проинициализировать строку.
Для выделения памяти под хранение строки могут использоваться функции динамического выделения памяти. При этом необходимо учитывать требуемый размер строки:
char *name; name = (char*)malloc(10); scanf("%9s", name);
Для ввода строки использована функция scanf(), причем введенная строка не может превышать 9 символов. Последний символ будет содержать '\0'.
Функции ввода строк
Для ввода строки может использоваться функция scanf(). Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат "%s" для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки.
Для ввода строки, включая пробелы, используется функция
char * gets(char *);
В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.
Функции вывода строк
Для вывода строк можно воспользоваться рассмотренной ранее функцией
printf("%s", str); // str - указатель на строку
или в сокращенном формате
printf(str);
Для вывода строк также может использоваться функция
int puts (char *s);
которая печатает строку s и переводит курсор на новую строку (в отличие от printf()). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки.
Функция ввода символов
Для ввода символов может использоваться функция
char getchar();
которая возвращает значение символа, введенного с клавиатуры. Указанная функция использовалась в рассмотренных ранее примерах для задержки окна консоли после выполнения программы до нажатия клавиши.
Функция вывода символов
Для вывода символов может использоваться функция
char putchar(char);
которая возвращает значение выводимого символа и выводит на экран символ, переданный в качестве аргумента.
Пример Посчитать количество введенных символов во введенной строке.
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() {
char s[80], sym;
int count, i;
system("chcp 1251");
system("cls");
printf("Введите строку: ");
gets(s);
printf("Введите символ: ");
sym = getchar();
count = 0;
for(i=0; s[i]!='\0'; i++)
{
if(s[i]==sym)
count++;
}
printf("В строке\n");
puts(s); // Вывод строки
printf("символ ");
putchar(sym); // Вывод символа
printf(" встречается %d раз",count);
getchar(); getchar();
return 0; }
Результат
выполнения
