Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык Си.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
868 Кб
Скачать
☆

Стандартные функции динамического выделения памяти

Функции динамического выделения памяти находят в оперативной памяти непрерывный участок требуемой длины и возвращают начальный адрес этого участка.

Функции динамического распределения памяти:

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; }

Результат выполнения