int n, a[n], i;
Лучше так не делать. Компилятор и не даст. Значение n должно быть известно при создании массива, а еще лучше быть предопределено в коде через define или const. И еще при объявлении переменной нужно сразу инициализировать ее через значение. Например, занулить все int.
Чтобы работало, объявление массива размером n, заданным пользователем, должно происходить после получения значения n:
int n = 0, i = 0, min = 0, max = 0;
printf("Введите n: ");
scanf("%d", &n);
int a[n]; /* а вот здесь компилятор не дает инициализировать статический массив с какими-либо значениями. */
/* Последующий код без изменений */
Еще б не помешала проверка на корректное введенное значение n:
int breakflag = 0;
printf("Введите n: ");
while (!breakflag) { // пока переменная, отвечающая за конец цикла == false
if (scanf("%d", &n) != 1) { // если сканф получил не целое число в пределах int
puts("Не целочисленное значение. Я устал, я мухожук.");
breakflag = 2; // некий код ошибки
} else if (n < 2 && n != -1) {
printf("Введите значение n > 2 или -1 для выхода: ");
} else {
breakflag = 1;
}
}
if (breakflag == 1) {
breakflag = 0; // для нулевого ретерна об успешной работе программы.
/* Код объявления и обработки массива*/
}
return breakflag;
}
Если заранее не известен размер массива, лучше бы пользоваться динамикой...
#include <stdlib.h>
/* код до создания массива*/
int* a = (int*)calloc(0, n * sizeof(int)); // создаем диамический массив размера n, заполняя его нулями.
// либо можно выделить память малоком и сделать memset();
if (a) {
/* Работаем с массивом как обычно, после проверки, что память выделилась. */
/* Либо можно работать по указателю, как в последнем примере. В таком случае */
/* понадобится простой указатель, который будет хранить нулевую ячейку а: */
// int *start_a = a;
// везде, где понадобится сброс указателя в начало, просто присваиваем
// a = start_a;
// в конце нужно чистить только память по указателю a.
}
// Когда память больше не нужна, чистим во избежание утечки, с проверкой, что указатель не NULL:
if (a) {
free(a);
}
// Память чистится только тогда, как была выделена память через одну из функций аллокации.
С динамическим массивом можно работать также, как со статическим, используя обращение имя массива[адрес элемента], но с многомерными массивами уже чуть сложнее и нужна внимательность.
указатель на динамический массив можно менять, например, через инкремент или декремент, но тогда желательно возвращать его на начальный элемент после обработки массива, если в дальнейшем этот массив еще будет обрабатываться.
Можно взять значение из ячейки динамического массива через унарный оператор *arr, это == arr[0] после создания массива. Можно использовать такую адресацию во время обработки: *(array+i) в качестве lvalue или rvalue.
При указании адреса в квадратных скобках внутри скобок можно производить любые действия для получения нужного адреса типа unsigned . Для изменения указателя динамического массива можно использовать только операции сложения и вычитания. например: array -= countA; или array += countB;
Просто так менять значения местами нельзя, нужна функция, которая это будет делать, либо писать ручками это каждый раз. Но в случае с указателями можно создать указатель и дать ему значение на любую другую переменную или значение элемента какого-то другого массива.
int a = 10, b = 20, *tmp_pointer = NULL;
tmp_pointer = &a; // теперь через (*tmp_pointer) можно получить актуальное
// значение a в момент обращения к указателю.
tmp_pointer = &b; // а теперь (*tmp_pointer) даст текущее значение b, либо
// запишет значение в переменную b
// при использовании (*tmp_pointer) в L-value.
Для примера чуть отредактирую код программы с использованием указателя. Указатель будет указывать на массив, все значения записывать, читать и сравнивать будем через указатель.
Если коротко, *ptr - работа со значением по указателю, ptr - сам указатель.
/* Код после получения значения n: */
int arr[n];
int *a = arr;
for(i = 0; i < n; i++) {
printf("a[%d] = ", i);
scanf("%d", a++); }
// после цикла с инкрементом указателя *a == arr[n-1]
a = arr; // сбрасываем на нулевую ячейку массива.
max = *a, min = *a; // здесь *a == arr[0]
for(i = 0; i < n; i++) {
if(*a > max) { max = *a; }
if(*a <= min) { min = *a; }
++a;
}
a = arr;
/* Вывод результатов */
/* чистить указатель не надо: он указывает на статический массив, а не динамически-выделенную память из кучи */
Напоследок еще стоит сказать: никогда не выходите за границы массива. ни для чтения, ни для записи. Ничего хорошего не получится из этого.
И напоминаю: Не забывайте возвращать указатель на начальное положение, очищать память на выходе, контролировать границы своей памяти и !NULL при работе с динамической памятью.