#include <stdio.h>
#include <stdint.h> // В частности, для uint16_t.

int main(void) {
	size_t nelem = 15;
	// volatile не нужон.
	uint16_t *testarray;
	// Кастить результат malloc нужно в плюсах, в сишечке void *
	// автоматически кастится в любой другой указатель.
	// sizeof() лучше делать для дереференснутого указателя, а не
	// для типа. Таким образом, если ты сменишь uint16_t на uint32_t,
	// код не сломается.
    testarray = malloc(sizeof(*testarray) * nelem);
    if (!testarray) {
    	fprintf(stderr, "malloc() failed\n");
    	exit(1);
    }
    
    // Как-то используем массив.
    
    // Захотели изменить его размер. Объявляем другой указатель, потому что
    // realloc() может сфейлиться и вернуть NULL. Если бы мы написали
    // testarray = realloc(...), то в таком случае была бы утечка памяти.
    uint16_t *temp;
    size_t temp_size;
    
    temp_size = nelem + 20; // Новая длина массива.
    temp = realloc(testarray, sizeof(*testarray) * temp_size);
    if (!temp) {
    	fprintf(stderr, "realloc() failed\n");
    	// Тут мы можем выйти или продолжить использовать testarray и nelem
    	// со старым размером.
    } else {
    	testarray = temp;
    	nelem = temp_size;
    }
    
    // Используем массив дальше.
    
	return 0;
}
