untonyst
@untonyst
Лентяй

Чем отличается динамическая переменная от переменной в блоке?

Немного странный вопрос, но почему-то он не дает мне покоя. Ответить на него я не могу, так как только начал изучать Си, но конкретного ответа в чем разница я найти не могу, ну кроме способов написания (это единственное в чем я пока вижу разницу :d).
Переменная в блоке "живет" только тогда, когда этот блок выполняется. А динамическая переменная - участок памяти, "метка". Вроде бы :d

Вариант первый:

#include <stdio.h>
#include <malloc.h>
#include <locale.h>

int main(void)
{
	setlocale(LC_ALL, "RUS");

	int a, b;
	
	printf("Введите значения для переменных \"a\" и \"b\": ");
	scanf("%d%d", &a, &b);
	printf("a = %d, b = %d\n", a, b);

	int *c = (int*)malloc(sizeof(int));
	*c = a;
	a = b;
	b = *c;
	free(c);

	printf("a = %d, b = %d", a, b);
	return 0;	
}


Вариант второй:

#include <stdio.h>
#include <locale.h>

int main(void)
{
	setlocale(LC_ALL, "RUS");

	int a, b;
	
	printf("Введите значения для переменных \"a\" и \"b\": ");
	scanf("%d%d", &a, &b);
	printf("a = %d, b = %d\n", a, b);

	{
		int c;
		c = a;
		a = b;
		b = c;
	}

	printf("a = %d, b = %d", a, b);
	return 0;	
}


И та, и другая переменная живут не вечно. Вопрос мой такой: "чем отличается переменная "с" в двух вариантах?".
  • Вопрос задан
  • 342 просмотра
Решения вопроса 1
15432
@15432
Системный программист ^_^
В первом случае c - указатель на выделенную область памяти в куче размером 4 байта. Переменная располагается в оперативной памяти (RAM) и для обращения к ней, процессор вынужден выполнять чтение и запись [относительно] медленной оперативной памяти.

Во втором случае c - локальная переменная, компилятор скорее всего превратит все действия по работе с ней в арифметические операции с регистрами процессора, обращение к которым на порядки быстрее, чем работа с ОЗУ.

примерный ассемблерный псевдокод в первом случае (смешал несколько архитектур :) не воспринимайте буквально)

mov r3, #4 //размер выделяемой области 4 байта
call malloc() //выделим память
mov r28, r3 //сохраним возвращенное значение адреса памяти
str r29, r28[0] //сохраним a (r29) в выделенную память (r28[0])
mov r29, r30 //присвоим a (r29) значение b (r30)
ldr r30, r28[0] //присвоим b значение *c
mov r3, r28 //адрес для очистки памяти
call free() //удаление выделенной области


следует заметить, что чтение и запись из ОЗУ - относительно медленные операции

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

mov r28, r29 //c = a
mov r29, r30 //a = b
mov r30, r28 //b = c
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Динамические переменные нужны, когда важно, чтобы переменная оставалась на месте. То есть, на неё что-то указывает:
struct Child {
    int data;
};
struct Parent {
    struct Child* child;
};
struct Child createChild(struct Parent* parent) {
    struct Child result;
    parent->child = &result;
    return result;  // parent->child будет указывать на мусор :(
}

На простые структуры обычно ничего не указывает. Мы свободно копируем их и используем так же, как использовали бы их составные части. Чем сложнее структура, тем выше вероятность, что её нельзя просто так взять и переместить в другую область памяти.
Ответ написан
@abcd0x00
Есть память, где работают все функции, перезатирая значения друг друга. А есть динамическая память, которая помечается занятой или освободившейся только через специальные действия.

Динамическая память, которая используется через malloc()/calloc()/realloc() и free(), нужна в двух случаях:
1) Когда ты не знаешь, сколько памяти тебе понадобится в какой-то момент. Например, не знаешь, какого точно размера массив будет, толи 100 элементов, толи 1000.
2) Когда нужно что-то сохранить в одной функции, а использовать в другой функции. Первая функция, завершаясь, никак не трогает то, что размещено в динамической памяти.

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

Если ты создал блок в функции, то он действует там же, где и остальные внутренности функции (её локальные переменные, её вызовы функций), просто там создаётся что-то вроде независимого куска, у которого отмечается время жизни, область видимости и так далее. Так что ты даже можешь сделать в нём переменные a и b, которые будут отдельными переменными со своими значениями на время жизни блока.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы