Динамическое выделение памяти в Си

Язык Си / Динамическое выделение памяти в Си

 

Очень часто возникают задачи обработки массивов данных, размерность которых заранее неизвестна. В этом случае возможно использование одного из двух подходов:

  • выделение памяти под статический массив, содержащий максимально возможное число элементов, однако в этом случае память расходуется не рационально;
  • динамическое выделение памяти для хранение массива данных.



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

 
int *p; // указатель на тип int


Начальный адрес статического массива определяется компилятором в момент его объявления и не может быть изменен.

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

 

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

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

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

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


Пример на Си: Организация динамического одномерного массива и ввод его элементов.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define _CRT_SECURE_NO_WARNINGS
#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 (см. рис.)
Матрица 3х4
Индекс выделенного элемента определится как

index = 1*4+2=6

 
Объем памяти, требуемый для размещения двумерного массива, определится как

n·m·(размер элемента)

Однако поскольку при таком объявлении компилятору явно не указывается количество элементов в строке и столбце двумерного массива, традиционное обращение к элементу путем указания индекса строки и индекса столбца является некорректным:

a[i][j] - некорректно.

Правильное обращение к элементу с использованием указателя будет выглядеть как

*(p+i*m+j),
где

  • p - указатель на массив,
  • m - количество столбцов,
  • i - индекс строки,
  • j - индекс столбца.

 

Пример на Си Ввод и вывод значений динамического двумерного массива

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#define _CRT_SECURE_NO_WARNINGS
#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;
}

Результат выполнения
Ввод и вывод значений динамического двумерного массива

Возможен также другой способ динамического выделения памяти под двумерный массив - с использованием массива указателей. Для этого необходимо:

  • выделить блок оперативной памяти под массив указателей;
  • выделить блоки оперативной памяти под одномерные массивы, представляющие собой строки искомой матрицы;
  • записать адреса строк в массив указателей.

Динамическое выделение памяти под двумерный массив

Графически такой способ выделения памяти можно представить следующим образом.
Выделение памяти под двумерный массив - графическое представление
При таком способе выделения памяти компилятору явно указано количество строк и количество столбцов в массиве.
Пример на Си

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#define _CRT_SECURE_NO_WARNINGS
#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");
  }
  // Очистка памяти
  for (i = 0; i < n; i++)  // цикл по строкам
    free(a[i]);   // освобождение памяти под строку
  free(a);
  getchar();   getchar();
  return 0;
}

Результат выполнения программы аналогичен предыдущему случаю.

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

Для размещения в оперативной памяти матрицы со строками разной длины необходимо ввести дополнительный массив m, в котором будут храниться размеры строк.

Пример на Си: Свободный массив

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#define _CRT_SECURE_NO_WARNINGS
#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)); // массив кол-ва элеменов в строках массива a
                     // Ввод элементов массива
  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");
  }
  // Освобождение памяти
  for (i = 0; i < n; i++)
  {
    free(a[i]);
  }
  free(a);
  free(m);
  getchar(); getchar();
  return 0;
}

Результат выполнения
Свободный массив

Перераспределение памяти

Если размер выделяемой памяти нельзя задать заранее, например при вводе последовательности значений до определенной команды, то для увеличения размера массива при вводе следующего значения необходимо выполнить следующие действия:

  • Выделить блок памяти размерности n+1 (на 1 больше текущего размера массива)
  • Скопировать все значения, хранящиеся в массиве во вновь выделенную область памяти
  • Освободить память, выделенную ранее для хранения массива
  • Переместить указатель начала массива на начало вновь выделенной области памяти
  • Дополнить массив последним введенным значением

Все перечисленные выше действия (кроме последнего) выполняет функция

 
void* realloc (void* ptr, size_t size);

  • ptr - указатель на блок ранее выделенной памяти функциями malloc(), calloc() или realloc() для перемещения в новое место. Если этот параметр равен NULL, то выделяется новый блок, и функция возвращает на него указатель.
  • size - новый размер, в байтах, выделяемого блока памяти. Если size = 0, ранее выделенная память освобождается и функция возвращает нулевой указатель, ptr устанавливается в NULL.

Размер блока памяти, на который ссылается параметр ptr изменяется на size байтов. Блок памяти может уменьшаться или увеличиваться в размере. Содержимое блока памяти сохраняется даже если новый блок имеет меньший размер, чем старый. Но отбрасываются те данные, которые выходят за рамки нового блока. Если новый блок памяти больше старого, то содержимое вновь выделенной памяти будет неопределенным.

 
Пример на Си Выделить память для ввода массива целых чисел. После ввода каждого значения задавать вопрос о вводе следующего значения.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <malloc.h>
int main()
{
  int *a = NULL, i = 0, elem;
  char c;
  do {
    printf("a[%d]= ", i);
    scanf("%d", &elem);
    a = (int*)realloc(a, (i + 1) * sizeof(int));
    a[i] = elem;
    i++;
    getchar();
    printf("Next (y/n)? ");
    c = getchar();
  } while (c == 'y');
  for (int j = 0; j < i; j++)
    printf("%d ", a[j]);
  if (i>2) i -= 2;
  printf("\n");
  a = (int*)realloc(a, i * sizeof(int)); // уменьшение размера массива на 2
  for (int j = 0; j < i; j++)
    printf("%d ", a[j]);
  getchar(); getchar();
  return 0;
}

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


Назад: Язык Си

Комментариев к записи: 99


  • Как в данном коде считать массив и если совпадет число с моим исходным, то заменить это число на ноль?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    int main(void)
    {
        int N = 0;
        int G = 0;
        int M = 0, mas[4][4] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };

        for (int i = 0; i < 4; i++) {
          for (int j = 0; j < 4; j++)
          {
            printf("%d ", mas[i][j]);
          }
          printf("\n");
        }
        printf("\n");
        for (int i = 0; i < 4; i++) {
          for (int j = i + 1; j < 4; j++)
          {
            N = (abs(mas[1][3]) + abs(mas[1][3]) + abs(mas[1][3]) + abs(mas[1][1]) + abs(mas[1][1]));
            printf("%d ", mas[i][j]);
          }
          printf("\n");
        }
        printf("\n");
        for (int i = 1; i < 4; i++) {
          for (int j = 0; j < i; j++) {
            printf("%d ", mas[i][j]);
            M = (abs(mas[1][2]) + abs(mas[1][2]) + abs(mas[1][3]) + abs(mas[1][3]) + abs(mas[1][3]) + abs(mas[3][1]) + abs(mas[3][1]));
          }
          printf("\n");
        }
        printf("%d ", N);
        printf("%d ", M);
        G = N - M;
        printf("\n");
        printf("%d ", G);
        printf("\n");
        }

  • Добрый день,кто может объяснить как выполняется данное задание адание: для заданной матрицы целых чисел выделить необходимый объем памяти на куче, заполнить значениями, вывести на экран элементы, которые являются локальными минимумами, и освободить выделенную память перед окончанием работы программы. Локальный минимум должен быть меньше либо равен своим соседям. Программа должна оперировать функциями для каждой из операций над матрицей, то есть, в программе необходимо реализовать: функцию выделения памяти под матрицу, функцию вывода матрицы на экран, функцию проверки соседей, функцию освобождения памяти. Для ввода
    4 4 10 3 5 1 9 2 7 3 12 6 8 2 20 9 11 5
    матрица будет иметь вид:
    10 3 5 1
    9 2 7 3
    12 6 8 2
    20 9 11 5
    вывод минимумов будет выглядеть так:
    1 2 2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>

    void allocate(/* нужные параметры указать тут */);
    void fill(/* нужные параметры указать тут */);
    void print(/* нужные параметры указать тут */);
    void release(/* нужные параметры указать тут */);
    void find_min(/* нужные параметры указать тут */);

    int main(int argc, char const *argv[])
    {
        int NO_OF_COLS = 0;
        int NO_OF_ROWS = 0;

        scanf("%d%d", &NO_OF_ROWS, &NO_OF_COLS);

        int ** matrix = NULL;

        allocate(/* нужные аргументы передавать сюда */);

        fill(/* нужные аргументы передавать сюда */);

        print(/* нужные аргументы передавать сюда */);
        
        find_min(/* нужные аргументы передавать сюда */);

        release(/* нужные аргументы передавать сюда */);

        assert(!matrix);
    }

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      #include <assert.h>
      #include <stdio.h>
      #include <stdlib.h>

      void allocate(/* нужные параметры указать тут */);
      void fill(/* нужные параметры указать тут */);
      void print(/* нужные параметры указать тут */);
      void release(/* нужные параметры указать тут */);
      void find_min(/* нужные параметры указать тут */);

      int main(int argc, char const *argv[])
      {
          int NO_OF_COLS = 0;
          int NO_OF_ROWS = 0;

          scanf("%d%d", &NO_OF_ROWS, &NO_OF_COLS);

          int ** matrix = NULL;

          allocate(/* нужные аргументы передавать сюда */);

          fill(/* нужные аргументы передавать сюда */);

          print(/* нужные аргументы передавать сюда */);
          
          find_min(/* нужные аргументы передавать сюда */);

          release(/* нужные аргументы передавать сюда */);

          assert(!matrix);
      }

  • Вот так я могу понять и думаю сам страуструп не будет против. Его тоже коробит работа с линейным массивом. Почему так я не спрашивал ))

    • Дмитрий
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      #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*));
        if (a==NULL) { printf("Память не выделена\n"); exit(1); }

        // Ввод элементов массива
        for (i = 0; i<n; i++)  // цикл по строкам
        {
          // Выделение памяти под хранение строк
          a[i] = (int*)malloc(m * sizeof(int));
              if (a[i]== NULL) { printf("Память не выделена\n"); n= i; goto ALARM; }
          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");
        }

        // Очистка
        ALARM:
        for (int ii = 0; ii < n; ii++)  // цикл по строкам
          free(a[ii]);   // освобождение памяти под строку
        free(a);
        getchar();   getchar();
        return 0;
      }

  • Вопрос.
    1
    int *a = (int*)malloc(n * sizeof(int));
    Обязательно ли здесь писать (int*)? Разве при присваивании приведение типа не будет произведено автоматически? Как здесь, например:
    1
    2
    int x = 123;
    double y = x;

    • Елена Вставская
      Нужно проверять для каждого конкретного компилятора. С приведением типа работает точно!

  • Елена, отлично написанная статья! Всё разложено по полочкам. Благодарю Вас!

  • Валерий
    У меня вопрос по свободным двумерным массивам(для строк). В вашем примере указано, что сперва нужно вводить размер строки. Но это ведь как бы не удобно. Вот я хочу допустим ввести 3 строки разной длины и я знаю заранее какой длины будет каждая строка. Получается мне тут не как не использовать свободный массив, а только фиксированной(максимальной) длины для строк?

    • Валерий
      Извините, вроде догадался. Мне получается сперва нужно нужно считать строку с помощью fgets, а потом определив длину данной строки, выделить под эту строку память и скопировать. Я правильно понял?

  • Здравствуйте, подскажите пожалуйста, free() в данном коде не работает, в чем ошибка? и можно ли использовать free() через указатели, без []?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    #include <clocale>
    #include <iostream>
    #include <malloc.h>
    #define S 5

    using namespace std;


    void two_dim_input(int** a)
    {
        srand(time(0));
        for (int i = 0; i < S; i++)
        {
            for (int u = 0; u < S; u++)
            {
                *((int*)a + i * S + u) = rand() % 99;
            }
        }
        
    }




    int main() 
    {

        int** mas = (int **)calloc(S, sizeof(*mas));
        for (int i = 0; i < S; i++)
            *(mas + i) = (int *)calloc(S, sizeof(mas));
        two_dim_input(mas);
        two_dim_output(mas);

        two_dim_sum(mas);
        printf("\n\n");
        two_dim_output(mas);
        for (int i = 0; i < S; i++)  // цикл по строкам
            free(mas[i]);   // освобождение памяти под строку
        free(mas);
        }

    • Елена Вставская
      1
      2
      3
      4
      5
      6
      7
      8
      *(*(a+i)+u)= rand() % 99;
      ...
      int** mas = (int**)calloc(S, sizeof(int*));
      for (int i = 0; i < S; i++)
        *(mas + i) = (int*)calloc(S, sizeof(int)); // не sizeof(mas)
      ...
      for (int i = 0; i < S; i++) // цикл по строкам
        free(*(mas+i)); // освобождение памяти под строку

  • Добро пожаловать У меня вопрос о динамическом распределении памяти, и я не знаю, как писать код. Вы можете помочь??? Вопрос: Дана строка. написать программу которая печатает самую короткую последовательность одинаковых символов

    • Елена Вставская
      Вводим строку. Объявляем 4 переменных: текущий счётчик и минимальный счётчик и позиция в строке (начало текущей последовательности и минимальной строки). Просматриваем все символы строки до конца (до 0). Если символ такой же, как предыдущий, увеличиваем текущий счётчик. Если нет, сравниваем текущий счётчик с минимальным, находим минимум, затем обнуляем текущий счётчик и перемещаем текущее начало строки. Когда строка просмотрена, выводим посимвольно, начиная с позиции минимальной строки количество символов, соответствующее минимуму.

  • Елена, здравствуйте. В Ваше примере не вижу проверки на то, выделил ли malloc память или нет. Проверка по типу:
    1
    2
    3
    a = (int**)malloc(n * sizeof(int*));
    if (!a)
    return (NULL);
    Касаемо этого у меня и имеется вопрос. Можно ли выходить из функции, которая возвращает массив указателей (двумерный массив) передавая в качестве параметра return (NULL)? Столкнулась с проблемой, что функция сегается в таком случае. К примеру:
    1
    2
    3
    4
    5
    6
    while (elem_arr[i]) //здесь идет чистка замоллоченной памяти
    {
      free(elem_arr[i]);
      i++;
    }
    return (NULL); // далее возвращаю NULL
    В результате этого программа сегается. Думала, что дело в неправильном использовании функции free, однако, если сделать exit(0) до return (NULL) программа спокойно выйдет. Подскажите, как правильно использовать NULL в таком случае

    • Елена Вставская
      По приведенному фрагменту кода затрудняюсь что-либо сказать

  • Добрый день! У меня есть такой простенький код C++ с ассемблерной вставкой. Скажите, как реализовать такой же алгоритм, но с динамическим выделением память под var. У самого не вышло:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    short var;

      cout << "_asm code started working" << endl;

      _asm {
        pushf   // помещаем регистр флагов в стек
        pop var // извлекаем операнд из стека (шта?)
      }

      cout << "_asm code finished working" << endl;

      // Вывод var
      cout << var << endl;

    • Елена Вставская
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      short *var;
      var = new short[1];
      cout << "_asm code started working" << endl;

      _asm {
      pushf // помещаем регистр флагов в стек
      pop *var[0] // извлекаем операнд из стека (шта?)
      }

      cout << "_asm code finished working" << endl;

      // Вывод var
      cout << *var[0] << endl;

  • Алексей
    Доброго времени суток. Подскажите пожалуйста, у меня есть динамический масив и его элементы нужно без цыкла заполнить одним значением (например 8).

  • Валерий
    Здравствуйте Елена, часто прибегаю к подсказкам из ваших примеров и объяснений, за что вам большое спасибо. Сам являюсь самоучкой, знакомство с Си начал примерно 1,5 года назад. И вот сегодня в первые узнаю, что заголовок <malloc.h> является не стандартным и вместо него рекомендуют использовать <stdlib.h>. Хотя знал, что функция malloc() может использовать любой из этих двух заголовков.

    • Елена Вставская
      На самом деле, зависит от компилятора. Чаще всего, если подключить "malloc.h", ошибки не будет. Но, например, Visual Studio позволяет подключить malloc.h внутри stdlib.h

  • Доброго времени суток Вам! Простите, что буду задавать вам глупые вопросы. Сын попросил помочь написать ему сортировку методом решета Эратосфена 3 с лишним млрд. простых чисел. Если реализовывать алгоритм в "классическом" виде, то время выполнения очень большое. Я предложил ему следующее "ускорение": 1. Заполнять массив только НЕчетными числами (ну кроме 2ки) - это уменьшило размер массива в 2 раза. 2. Попытаться при каждом проходе удалять "Ненужные" элементы массива, для того чтобы при каждом последующем проходе уменьшать количество просматриваемых элементов. НО. Сын мне объяснил, что такие фокусы в Си не проходят. Так вот вопрос: массив ведь не единственный вид данных в Си, может существует вид данных, который позволяет получить данные по индексу и при этом позволяет динамически удалять элементы, без последующей перезаписи всей цепочки элементов?

    • Елена Вставская
      Существует структура данных "список" с последовательным доступом. В ней удаление элементов проще реализовать.

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <malloc.h>

    int main()
    {
        system("chcp 1251"); system("cls");
        srand(time(NULL));
        int* b, n, m;
        printf("кол-во строк: "); scanf_s("%d", &n);
        printf("кол-во столбцов: "); scanf_s("%d", &m);
        b = (int*)malloc(n * m * sizeof(int));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) 
                *(b + i * m + j) = rand() % 100;
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                printf("%4d", *(b + i * m + j));
            }
            printf("\n");
        }
        int max, maxi = 0, maxj = 0;
        max = *b;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                if (*(b + i * m + j) == max) {
                continue;
                }
                else if (*(b + i * m + j) > max) {
                    max = *(b + i * m + j);
                    maxi = i;
                    maxj = j;
                }
        }
        printf("\nMax = %d", max);
        printf("\nmaxi = %d", maxi);
        printf("\nmaxj = %d", maxj);

        if (maxi > 0) { 

            for (int i = maxi; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    *(b + (i - 1) * m + j) = *(b + i * m + j); 
                }
            }
            n--;
            printf("\nматрица после удаления строки\n\n");
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    printf("%4d", *(b + i * m + j));
                }
                printf("\n");
            }
            m++;
            for (int i = 0; i < n; i++) {
                for (int j = m - 1; j > maxj - 1; j--) {
                    *(b + i * m + j) = *(b + i * m + (j  - 1)); //зміщуємо стовбчики вправо
                }
            }
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    *(b + i * m + maxj) = rand() % 100;
                }
            }
            printf("\nматрица после добавления столбца\n\n");
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    printf("%4d", *(b + i * m + j));
                }
                printf("\n");
            }
            return 0;
        }
        else return 0;
    }
    Не коректно работает удаление столбца и заполнение нового. Помогите пожалуйста!

    • Елена Вставская
      Насколько я поняла, нужно удалить строку и столбец, на пересечении которых находится максимум:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
          for (int i = maxi; i < n-1; i++) {
            for (int j = 0; j < m; j++) {
              *(b + i * m + j) = *(b + (i+1) * m + j);
            }
          }
          n--;
          printf("\nматрица после удаления строки\n\n");
          for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
              printf("%4d", *(b + i * m + j));
            }
            printf("\n");
          }
          for (int i = 0; i < n; i++) {
            for (int j = 0; j < maxj; j++) {
              *(b + i * (m-1) + j) = *(b + i * m + j); //сдвигаем столбцы влево
            }
            for (int j = maxj+1; j < m; j++) {
              *(b + i * (m-1) + j-1) = *(b + i * m + j); //сдвигаем столбцы влево
            }
          }
          m--;
          printf("\nматрица после удаления столбца\n\n");
          for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
              printf("%4d", *(b + i * m + j));
            }
            printf("\n");
          }

      • извините там нужно добавить столбец после столбца с максимальным елемнтом и заполнить этот столбец рандомными значениями

        • Елена Вставская
          Надеюсь, уже справитесь самостоятельно :) Суть в том, что при добавлении или удалении столбца и таком способе выделения памяти смещаются все элементы массива (кроме тех, которые стоят до изменяемого столбца в начальной строчке)

  • Удалить из массива строку которая находится перед строкой с максимальным элементом и добавить столбец после столбца с максимальным элементом.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <malloc.h>

    int main()
    {
        system("chcp 1251"); system("cls");
        srand(time(NULL));
        int* b, n, m;
        printf("кол-во строк "); scanf_s("%d", &n);
        printf("кол-во столбцов: "); scanf_s("%d", &m);
        b = (int*)malloc(n * m * sizeof(int));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) 
                *(b + i * m + j) = rand() % 100;
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                printf("%4d", *(b + i * m + j));
        }
        int max, maxi = 0, maxj = 0;
        max = *b;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                if (*(b + i * m + j) == max) {
                continue;
                }
                else if (*(b + i * m + j) > max) {
                    max = *(b + i * m + j);
                    maxi = i;
                    maxj = j;
                }
        }
        printf("\nMax = %d", max);
        printf("\nmaxi = %d", maxi);
        printf("\nmaxj = %d", maxj);
    }
    дальше не знаю что делать помогите пожалуйсто

  • Здравствуйте, есть задание : заданы две одинаковые матрицы, требуется одну из них записать вниз во вторую, используя функцию realloc, я не так давно изучаю программирование, поэтому не понимаю почему мой код не работает, не могли бы вы указать на ошибку ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    #define _CRT_SECURE_NO_WARNINGS
    #include "stdlib.h"
    #include "stdio.h"
    #include "conio.h"
    #include "math.h"
    #include <malloc.h>
    #include "locale.h"
    #include "string.h"
    #include "windows.h"
    #include "time.h"

    int main()
    {
        int** a;  // указатель на указатель на строку элементов
        int** b;  // указатель на указатель на строку элементов
        int i, j, n, m;
        int counter = 0;
        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");
        }

        b = (int**)malloc(n * sizeof(int*));
        // Ввод элементов массива
        for (i = 0; i < n; i++)  // цикл по строкам
        {
            // Выделение памяти под хранение строк
            b[i] = (int*)malloc(m * sizeof(int));
            for (j = 0; j < m; j++)  // цикл по столбцам
            {
                printf("a[%d][%d] = ", i, j);
                scanf("%d", &b[i][j]);
            }
        }

        for (i = 0; i < n; i++)  // цикл по строкам
        {
            for (j = 0; j < m; j++)  // цикл по столбцам
            {
                printf("%5d ", b[i][j]); // 5 знакомест под элемент массива
            }
            printf("\n");
        }
        
        a = (int**)realloc(a, (2*n*m) * sizeof(int));

        for (i = n; i < 2*n; i++)  // цикл по строкам
        {
            for (j = 0; j < m; j++)  // цикл по столбцам
            {
                a[i][j] = b[counter][j];
                counter++;
            }
            printf("\n");
        }

        for (i = 0; i < 2*n; i++)  // цикл по строкам
        {
            for (j = 0; j < m; j++)  // цикл по столбцам
            {
                printf("%5d ", a[i][j]); // 5 знакомест под элемент массива
            }
            printf("\n");
        }

        // Очистка памяти
        for (i = 0; i < n; i++)  // цикл по строкам
            free(a[i]);   // освобождение памяти под строку
        free(a);

        for (i = 0; i < n; i++)  // цикл по строкам
            free(b[i]);   // освобождение памяти под строку
        free(b);

        getchar();  
        return 0;
    }

    • Елена Вставская
      Насколько я понимаю, должно быть так:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      a = (int**)realloc(a, 2*n * sizeof(int*));
      for (i = n; i < 2*n; i++) // цикл по строкам
      {
        a[i] = (int*)malloc(m * sizeof(int));
        for (j = 0; j < m; j++) // цикл по столбцам
        {
          a[i][j] = b[counter][j];
          counter++;
        }
      }

  • Дмитрий Внуков
    Здравствуйте. Задание:В матрице размером NxM упорядочить элементы столбцов, не содержащих нулевых элементов по возрастанию методом выбора. Можете пожалуйста объяснить, почему в данном случае без помощи костыля(это момент, где я заставляю прогнать весь фрагмент с обработкой дважды) матрица сортируется не до конца? Остаются моменты где не хватает 1-2 замен.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    #include "stdafx.h"
    #include "math.h"
    #include "windows.h"
    #include "stdlib.h"
    #include <locale.h>
    int _tmain(int argc, _TCHAR* argv[])
    {  setlocale(0,"rus");
      int i,j,i_,j_,N,M,*A,buf,min=10000,k,d=0;
      printf("Введите размеры матрицы A");
      scanf("%i %i",&N,&M);

    A = (int*)malloc(N*M * sizeof(int));

    printf("Матрица:\n");
    for(i=0;  i<N; i++)
    {printf("\n");
    for(j=0; j<M; j++)
      {*(A+i*N+j)=-2 + rand()%(2-(-2)+1); 
    printf("%2i    ",*(A+i*N+j));}}

    do{d++;

      for(j=0; j<M; j++)
    {for(k=0; k<N-1; k++) {min=k;
    for(i=k+1;  i<N; i++){
      if (*(A+i*N+j)==0 || *(A+min*N+j)==0) {continue;} 
      if (*(A+min*N+j)<*(A+i*N+j)) {min=i;}
    else{  buf=*(A+min*N+j);
        *(A+min*N+j)=*(A+i*N+j);
        *(A+i*N+j)=buf;}}}}

    }while (d<2);

    printf("\n Преобразование:");
    for(i=0;  i<N; i++)
    {printf("\n");
    for(j=0; j<M; j++)
      printf("%2i    ",*(A+i*N+j));}
    printf("\n");
     system("pause");
      return 0;
    }

    • Елена Вставская
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      printf("Матрица:\n");
        for (i = 0; i < N; i++)
        {
          printf("\n");
          for (j = 0; j < M; j++)
          {
            *(A + i * M + j) = -2 + rand() % (2 - (-2) + 1);
            printf("%2d ", *(A + i * M + j));
          }
        }

        for (j = 0; j < M; j++)
        {
          int has0 = 0;
          for (k = 0; k < N; k++)
          {
            if (*(A + k * M + j) == 0)
            {
              has0 = 1; break;
            }
          }
          if (has0 == 1) continue;
          for (k = 0; k < N - 1; k++)
          {
            min = k;
            for (i = k + 1; i < N; i++)
            {
              if (*(A + i * M + j) < *(A + min*M + j))
              {
                min = i;
              }

            }
            int buf = *(A + k * M + j);
            *(A + k * M + j) = *(A + min * M + j);
            *(A + min * M + j) = buf;
          }  
        }

  • Подскажите, пожалуйста, в чем ошибка. Нужно возвести квадратную матрицу А в степень, задаваемую с клавиатуры.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    #include <stdio.h>
    #include <conio.h>
    #include <malloc.h>
    #include <stdlib.h>
    int main() {
        int i, j, k, s, m;
        printf("Power: ", s);
        scanf_s("%d", s);
        double *a;
        double b[3][3];
        a = (double*)malloc(3 * 3 * sizeof(double));
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                printf("a[%d][%d] = ", i, j);
                scanf_s("%lf", (a + i * 3 + j));
            }
        }
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                printf("%.2lf ", (a + i * 3 + j));
            }
            printf("\n");
        }
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++)
            {
                b[i][j] = 1;
                for (m = 1; m <= s; m++) {
                        b[i][j] *= a[j][i];
            }
        }
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                printf("%.3lf ", (b + i * 3 + j));
            }
            printf("\n");
        }
        free(a);
        free(b);
        _getch();
        return 0;
    }

    • Елена Вставская
      Она тут не одна :)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      #include <stdio.h>
      #include <conio.h>
      #include <malloc.h>
      #include <stdlib.h>
      int main() 
      {
        int i, j, k, s, m;
        printf("Power: ");
        scanf_s("%d", &s);
        double* a;
        double b[3][3];
        a = (double*)malloc(3 * 3 * sizeof(double));
        for (i = 0; i < 3; i++) {
          for (j = 0; j < 3; j++) {
            printf("a[%d][%d] = ", i, j);
            scanf_s("%lf", (a + i * 3 + j));
          }
        }
        for (i = 0; i < 3; i++) {
          for (j = 0; j < 3; j++) {
            printf("%.2lf ", *(a + i * 3 + j));
          }
          printf("\n");
        }
        for (i = 0; i < 3; i++) {
          for (j = 0; j < 3; j++)
          {
            b[i][j] = 1;
            for (m = 1; m <= s; m++) {
              b[i][j] *= *(a + i * 3 + j);
            }
          }
        }
          for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
              printf("%.3lf ", b[i][j]);
            }
            printf("\n");
          }
          free(a);
          _getch();
          return 0;
        }

  • Информатик
    Здравствуйте, программа с i и j работает, заменил i и j на count1 count2 и работать перестало. Как так?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    #include <stdio.h>
    #include <stdlib.h>
    #include "locale.h"
    #include <malloc.h>
    #include <math.h>
    #define _CRT_SECURE_NO_WARNINGS

    double func(int n,int m,double **arr,int count1,int count2,double changer);

    int main()
    {
    int count1=0,count2=0,n=0,m=0;
    double changer=0;
    double **arr;

    printf("Введите количество строк: ");
    scanf("%d", &n);
    printf("Введите количество столбцов: ");
    scanf("%d", &m);

    arr = (double*)malloc(n*m * sizeof(double));

    for (count1=0;count1<n;count1++)
    {
    for (count2=0;count2<m;count2++)
    {
    printf("arr[%d][%d] = ", count1, count2);
    scanf("%fl", (arr + count1*m + count2));
    printf("%lf\t",*(arr + count1*m + count2));
    }
    printf("\n");
    }

    for (count1=0;count1<n;count1++)
    {
    for (count2=0;count2<m;count2++)
    {
    printf("%lf\t",*(arr + count1*m + count2));
    }
    printf("\n");
    }

    func(arr,count1,count2,changer,n,m);
    printf("\n");

    for (count1=0;count1<n;count1++)
    {
    for (count2=0;count2<m;count2++)
    {
    printf("%lf\t",*(arr + count1*m + count2));
    }
    printf("\n");
    }
    }

    double func(int n,int m,double **arr,int count1,int count2,double changer)
    {
    for (count2=0;count2<m;count2++)
    {
    changer=arr[0][count2];
    for (count1=0;count1<n-1;count1++)
    {
    arr[count1][count2]=arr[count1+1][count2];
    }
    arr[n-1][count2]=changer;
    }
    return **arr;
    }

    • Елена Вставская
      Чтобы ответить, нужен исходный код с i, j. Возможно, при замене где-то произошла опечатка

  • Здравсвуйте, хотел спросить. Существует ли функция, благодаря которой мы можем удалять и прибавлять элементы без нашего участия. (Т.е. как в питоне (имя массива.append)

  • Здравствуйте, подскажите если память выделена в main, а расширение памяти realloc в функции get_string() при выходе из функции память затирается автоматически без использования функции free(), можно ли это обойти?

    • Елена Вставская
      Да, можно, если вернуть из функции указатель на вновь выделенную память

  • Владислав
    Здравствуйте. Спасибо за ваш труд! Хотелось бы задать вопрос: а как при выделении памяти, при которой компилятору явно указано количество строк и количество столбцов в массиве(пример с Вашего сайта) воспользоваться функцией realloc для расширения границ массива, в случае со строками и со столбцами, отдельно?

    • Елена Вставская
      Если память выделяется единым массивом для последовательного хранения всех строк, то воспользоваться функцией realloc затруднительно. В случае если память выделяется в два этапа (сначала для указателей на строки, а затем для самих строк), функцией realloc придется воспользоваться отдельно для расширения массива указателей на строки и отдельно для перераспределения памяти под элементы каждой строки.

      • Владислав
        Как я понимаю в данном случае:
        1
        2
        3
        4
        5
        6
        int **mass;
          mass = (int**)malloc(n * sizeof(int*));
          for (int i = 0; i < n; i++)
            {
              mass[i] = (int*)malloc(m * sizeof(int));
            }
        происходит выделение памяти в два этапа, значит для расширения массива(на одну строку) функцией realloc придется воспользоваться отдельно для расширения массива указателей на строки и отдельно для перераспределения памяти под элементы каждой строки. Но, к сожалению, не получилось прийти к правильной реализации:
        1
        2
        3
        4
        5
        mass = (int**)realloc(NULL, (n+1) * sizeof(int*));
          for (int i = 0; i < (n+1); i++)
            {
              mass[i] = (int*)realloc(NULL,m * sizeof(int));
            }

        • Елена Вставская
          Конечно, realloc() работает с уже выделенной памятью, поэтому для вновь добавленных строк память надо выделить функцией calloc() или malloc(), а функцию realloc() использовать только для старых строк

          • Владислав
            Попробовал реализовать эту ситуацию, но опять ждала неудача:
            1
            2
            3
            4
            5
            mass = (int**)realloc(mass, (n+1) * sizeof(int*));
            for (int i = 0; i < (n+1); i++)
                {
                  mass[i] = (int*)malloc(m * sizeof(int));
                }

          • Елена Вставская
            Стёрлись все элементы :)
            1
            2
            mass = (int**)realloc(mass, (n+1) * sizeof(int*));
            mass[n] =(int*)malloc(m * sizeof(int));
            Это если добавилась одна строка. Если добавились строка и столбец, то
            1
            2
            3
            4
            5
            6
            mass = (int**)realloc(mass, (n+1) * sizeof(int*));
            mass[n] =(int*)malloc((m+1)* sizeof(int));
            for (int i = 0; i < n; i++)
            {
            mass[i] = (int*)realloc(mass[i], (m+1)* sizeof(int));
            }

          • Владислав
            Огромное спасибо! Теперь все встало на свои места.


  • Как происходит обращение к элементу в статическом массиве, и как в динамическом. И зачем нам статический массив если есть динамический (простоту использования и уделение внимания на очистку динамического массива не учитывать)

    • Елена Вставская
      В некоторых случаях выполнение операций выделения и очистки памяти не учитывать не получается. А иногда нужно привязать массив к размещению в определенной ячейке памяти.

  • Елена, добрый день! Подскажите, пожалуйста. В случае использования int **a для выделения памяти для двумерного массива, единица хранения для a это 8 байт (для 64 разрядной архитектуры) - это понятно. А какова единица хранения для *a? У меня *a и *(a+1) всегда 32, независимо от типа (int, char) и количества строк и столбцов.

    • Елена Вставская
      Да, верно. Любой указатель занимает 4 байта, независимо от типа.

  • Как вы заменили на char только в объявлении? А выделении памяти в sizeof тоже char поставили? Если вы оставили там инт или ошиблись и поставили char* вместо просто char, то у вас будет выделяться два байта под инт, а вы будете идти в массив шагами по одному байту (char). Ещё битность программы какая?

  • Добрый день! Этот же способ подойдет для создание динамичного массива, состоящего из символов? Я использовала первый пример и просто попробовала заменить int на char. Работает через раз. В том плане, что когда программа заходит в цикл, чтобы ввести элементы массива, то она игнорирует 1 шаг и сразу переходи ко второму, затем сразу переходит к 3 шагу. Для работы с char есть какие то особые правила? Я делала разные типы циклов, думая, что где-то косячу с шагом, но ничего не изменилось. В моем заданием мне нужно, чтобы пользователь ввел в массив символы и я могла найти среди них определенные. Заранее

  • Елена, добрый день! Как я понимаю, функции calloc, malloc и realloc выделяют память в общей куче, а не в стеке. Есть возможность как-то заранее проверить: есть ли место в стеке, и если есть, то выделить память там, если нет - проверить, есть ли место в общей куче и если есть, то выделить память там, иначе - сообщение об ошибке. И в продолжении вопроса: в языке с++ есть тип vector, который уже содержит в себе возможности функций malloc. Можно ли при помощи типа vector выделить в ОС Виндос память, большую чем 2 Гб (разумеется, при этом свободной ОЗУ подразумевается гораздо больше). И можно ли тоже самое сделать напрямую через функцию malloc?

  • Антонина
    Елена, добрый день! 1. Для чего в примерах программ включена библиотека malloc.h, если stdlib.h содержит все используемые функции выделения и освобождения памяти?
    2.В чем разница между функциями malloc и calloc?
    3.В приведенных примерах программ в части ввода элементов массива при использовании функции scanf в списке аргументов в некоторых указывается амперсанд (&) - организация динамического одномерного массива, двумерного массива с использованием указателей, свободного массива, но в обычном динамическом двумерном массиве нет. Почему?
    Заранее спасибо за ответы!

    • Елена Вставская
      1. Не все компиляторы включают библиотеку malloc.h внутри stdlib.h.
      2. Функция calloc при выделении памяти обнуляет ее содержимое и, соответственно, выполняется несколько дольше.
      3. Аргументом функции scanf является адрес. Амперсанд указывается в аргументе scanf если мы работаем с переменной (в этом случае амперсанд - это адрес переменной), а не с указателем. Если мы выделяем единую область памяти под двумерный массив, то обращаться к его элементам через индексы строки и столбца не получится, т.к. в этой единой области памяти не указано явно, сколько в массиве строк и сколько столбцов. В этом случае приходится обращаться к элементам массива через указатель (a+i*m+j), где m - количество столбцов. А этот указатель как раз и является адресом элемента a[i][j].

      • Антонина
        Елена, добрый день! Спасибо еще раз за ответы. У меня есть еще одно недопонимание по этой статье. Как программа понимает, что a - это массив? При инициализации мы указываем просто указатель a и переменные. В статье про массивы говорится «часто требуется задавать значения элементов массива в процессе выполнения программы. При этом используется объявление массива без инициализации. В таком случае указание количества элементов в квадратных скобках обязательно.» Что является объявлением массива в программах данной статьи? Например, в примере организации одномерного массива a как массив начинает фигурировать аж в 19 строке как аргумент функции scanf. Спасибо!

        • Антонина
          Или объявлением массива является использование функции динамического выделения памяти, так как данная функция предполагает работу только с массивами?

          • Елена Вставская
            Массив - это непрерывная область памяти, хранящая элементы одинакового типа. Массив можно объявить статически, указав количество элементов в квадратных скобках, или динамически. Во втором случае мы объявляем указатель (то есть переменную, которая хранит адрес). Функция динамического выделения памяти ищет непрерывный участок памяти требуемой длины и возвращает адрес начала этого участка. Этот адрес и присваивается указателю, после чего мы можем работать с динамически выделенной памятью через указатель.

  • Алексей
    Не удается реализовать алгоритм нахождения числа делителей у массива,прошу помощи в этом деле.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <stdio.h>
    #include <stdlib.h>
    #include <conio.h>


    void sort()//функция нахождения числа делителей и сортировки
    {

    }

    int main(void) {
        int n;
        int m;
        m = 0;
        printf("a[n],n=...\n");//число элементов в массиве
        scanf("%i", &n);
        int a[n];
        int i;
        for (i = 0; i < n; i++)//задание значений каждого из элементов
        {
            printf("number %i=", i);
            scanf("%i", &a[i]);
        }
        sort(a, n);//выполнение функции по сортировке элементов массива
        for (int i = 0; i < n; ++i)/*вывод элементов в порядке возрастания их 
                                                                    числа делителей*/

        {
            printf("%i ", a[i]);
        }
        getch();
        return 0;


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    #include <stdio.h>
    /*Однако мне удалось реализовать алгоритм поиска делителей отдельного числа*/

    int main(void) {
        int x;
        int i;
        int m;
        m = 0;
        printf("enter x...");
        scanf("%i", &x);//прием значения переменной с клавиатуры
        for (i = 1; i <= x; i++)/*цикл для вычисления числа делителей 
                     заданной переменной*/

        {
            if (x % i == 0)
                m++;
        }
        printf("m=%i", m);//вывод числа делителей
        return 0;
    }

    • Елена Вставская
      Идея такая, что нужно создать ещё один массив целых чисел, и заполнить его значениями m количества делителей. Потом сортировать уже получившийся массив по возрастанию значений m, а параллельно с ним переставлять значения исходного массива.

      • Здравствуйте. Мне нужно поменять местами элементы главной и побочной диагоналей, без выделения динамической памяти это делается так:
        1
        2
        3
        4
        5
        6
        for (int i = 0; i < N; i++)
          {
            float m = A[i][i];
            A[i][i] = A[i][N - i - 1];
            A[i][N - i - 1] = m;
          }
        Как только пытаюсь добавить указатели и общение к элементам массива таким образом:
        1
        2
        3
        4
        5
        6
        for (int i = 0; i < N; i++)
          {
            float m = *(A + i * N + i);
            *(A + i * N + i) = *(A + i * N - i - 1);
            *(A + i * N - i - 1) = m;
          }
        ничего не работает, подскажите, пожалуйста, в чём проблема.

        • Елена Вставская
          Думаю, что ошибка не в этом участке кода. Чтобы обращаться к массиву через указатель, надо выделить под него память динамически. Чтобы подсказать, где ошибка, нужен код целиком.

          • Мне кажется, что ошибка в отсутствии "sizeof". Индекс статического массива индексируется с шагом размера ячейки. При обращении к памяти, нужно это сделать самому типа *(sizeof(float)*(A+i*N-i-1)) = m;

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


      • Дмитрий
        я же в самом комментарии привел пример использования, написание функции для обработки массива, например при создании библиотеки, обращаться к массиву через [i][j] уже не получится, но я уже дошел до ответа методом проб и ошибок.
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        void showMass(int **point, unsigned char R, unsigned char C)
        {
          for(unsigned char i = 0; i < R; i++)
          {  
            for(unsigned char j = 0; j < C; j++)
          {
              printf(" %5d ", *(*(point + i) + j));
            }
            printf("\n");
          }
        }
        ну и вызов функции как 
        showMass(&data[0], r, c);
        P.S. r c аналог ваших n m (Rows, Columns)

        • Елена Вставская
          Ну, да, можно и так. Только не пойму, почему через p[i][j] не получится?

  • Добрый день. Объясните пожалуйста значение строки: a = (int*)malloc(n*m * sizeof(int)); Зарание спасибо.

    • Елена Вставская
      Функция malloc() предназначена для динамического выделения памяти. В качестве аргумента ей передается количество байт, которые надо выделить. Оно вычисляется как n строк по m столбцов, где каждый элемент занимает 4 байта. В общем случае количество байтов, занимаемых одним элементом, определяется с помощью функции sizeof(), которой в качестве аргумента передается объект, размер которого в байтах необходимо определить. Возвращаемое значение функции malloc - указатель на неопределенный тип, или начальный адрес выделенного участка памяти. И этот указатель необходимо привести к указателю того типа данные которого будут храниться в массиве. В данном случае это указатель на int - (int*)

  • В самом первом примере (выделение памяти для одномерного массива) есть одна маленькая неточность: вводимый элемент не проверяется на "не цифру", в результате чего при наборе "буква + Enter" (у меня так случайно вышло) программа входит в бесконечный цикл. Я думаю, что в данном примере такая проверка не обязательна, но комментарий по этому поводу не был бы лишним, тем более, что далеко не все читатели Вашего замечательного сайта (и я в том числе) - специалисты в Си. Вы, Елена, делаете работу, достойную всяческих комплиментов.

  • Дмитрий
    Классные уроки по языку С! Очень понравились. Все доступно и наглядно представлено!

  • Добрый день! Почему в последнем примере мы <span class='prog'>getchar()</span> пишем два раза
    1
    2
    3
    getchar();
        printf("Next (y/n)? ");
        c = getchar();
    Почему, если мы напишем один раз, то программа не останавливается и не ждет нашего ввода?

    • Елена Вставская
      Мы в цикле вызываем функцию scanf() для ввода элементов массива (строка 10). Эта функция считывает, в данном случае, числовое значение до символов "пробел", "табуляция" или "перевод строки". При этом сам "перевод строки" остаётся в буфере обмена. Поэтому если не поставить дополнительный getchar() (строка 14), то этот "перевод строки" из буфера будет воспринят в качестве символа для продолжения ввода. Дополнительный getchar() "гасит" "перевод строки" из буфера и позволяет пользователю ввести символ с клавиатуры.
      Аналогичным образом действует двойной getchar() в конце программы.

      • Зелимхан
        > При этом сам «перевод строки» остаётся в буфере обмена. Елена, от куда он там берется в буфере? "Перевод строки"...

        • Елена Вставская
          Перевод строки состоит из двух символов с кодами 13, 10 (перевод строки, возврат каретки). При этом один из них заканчивает ввод, а второй остается в буфере и автоматически считывается при следующем вводе символа или строки. Если вводятся подряд несколько чисел, то scanf() этот символ из буфера игнорирует, поскольку ждет ввода числа.

          • В конце пограммы, чтобы консоль не схлопывалась я пишу: System("PAUSE"); По-моему, так удобнее и информативнее

  • здравствуйте у меня такой вопрос и мне нужен помощь.Написать программу которая печатает самое краткое слово строки.. и я это сделал... а теперь для этого вопрос, мне надо выделить память с помощью malloc и calloc... но не знаю как..  

    • Елена Вставская
      Если Вы знаете, сколько букв содержится в слове (N), то выделить память можно так: char *slovo = (char*) malloc(N+1);


  • Подскажите пожалуйста, могу ли я выделить память во время ввода новых элементов? То есть я не с самого начала задаю размерность, а постепенно могу ее увеличивать вводя новый символ, и аналогично уменьшать, удаляя пустые места в памяти? Вот пример кода. Задача: записать в массив и вывести на экран все целые числа, которые введены в консоль.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <iostream>
    #include <conio.h>
    #define ESC 27
    #define EOS ′\n′
    using namespace std;
    int main() {
      int *a, temp = 0, i = 0;
      a = (int*)malloc(temp*sizeof(int));
      do {
        cout << "Enter Numbers: ";
        do {
          cin >> a[temp];
          temp++;
        } while (cin.get() != EOS);
        cout << "Result achived: ";
        for (i, temp; temp > 0; temp−−, i++) {
          cout << a[i] << " ";
        }
      } while (_getch() != ESC);
      return 0;
    }

    • Елена Вставская
      Борис, в соответствии с Вашим вопросом дополнила статью.

      • Спасибо! Долго ждал вашего ответа, но уже нашел решение:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        #include <conio.h>
        #define ESC 27
        #define EOS '\n'
        using namespace std;
        int main() {
          int *a, temp, i;
          do {
            system("CLS");
            temp = 0, i = 0;
            a = (int*)malloc(sizeof(int));
            cout << "Enter Numbers:  ";
            do {
              cin >> a[temp];
              temp++;
              if (temp >= (sizeof(a) / sizeof(*a)))
                a = (int*)realloc(a, (temp + 1) * sizeof(int));
            } while (cin.get() != EOS);
            cout << "Result achived: ";
            for (i, temp; temp > 0; temp--, i++)cout << a[i] << " ";
            free(a);
          } while (_getch() != ESC);
          return 0;
        }

  • Информатик
    Здравствуйте,не могли бы вы пояснить,почему в данном случае мы не объявляем массив и почему используем указатель "а", как имя массива?:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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]);
        }

    • В данном примере используется динамическое выделение памяти, то есть память выделяется на этапе выполнения программы. Объявляется указатель, в который позже запишется адрес выделенного участка памяти требуемого объема. Выделением памяти занимается функция malloc(). Если бы мы объявили массив, то мы имели бы дело со статическим массивом, в котором максимальное количество элементов задано на этапе компиляции.

  • Здравствуйте. Объясните пожалуйста почему в указателе две звёздочки? (int **a);

    • Читайте чуть выше. В данном случае a представляет собой указатель на массив указателей, каждый из которых, в свою очередь, указывает на свой массив элементов строки.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *