2. Инициализация массивов
Как и простые переменные, массивы могут быть инициализированы при объявлении. Инициализатор для объектов составных типов (каким является массив) состоит из списка инициализаторов, разделенных запятыми и заключенных в фигурные скобки. Каждый инициализатор в списке представляет собой либо константу соответствующего типа, либо, в свою очередь, список инициализаторов. Эта конструкция используется для инициализации многомерных массивов.
Наличие списка инициализаторов в объявлении массива позволяет не указывать число элементов по его первой размерности. В этом случае количество элементов в списке инициализаторов и определяет число элементов по первой размерности массива. Тем самым определяется размер памяти, необходимой для хранения массива. Число элементов по остальным размерностям массива, кроме первой, указывать обязательно.
Если в списке инициализаторов меньше элементов, чем в массиве, то оставшиеся элементы неявно инициализируются нулевыми значениями. Если же число инициализаторов больше, чем требуется, то выдается сообщение об ошибке.
Примеры инициализации массивов:
nt a[3] = {0, 1, 2}; |
// Число инициализаторов равно числу элементов |
double b[5] = {0.1, 0.2, 0.3}; |
// Число инициализаторов меньше числа элементов |
int c[ ] = {1, 2, 4, 8, 16}; |
// Число элементов массива определяется по числу инициализаторов |
int d[2][3] = {{0, 1, 2}, {3, 4, 5}}; |
// Инициализация двумерного массива. Массив состоит из двух строк, // в каждой из которых по 3 элемента. Элементы первой строки // получают значения 0, 1 и 2, а второй – значения 3, 4 и 5. |
int e[3] = {0, 1, 2, 3}; |
// Ошибка – число инициализаторов больше числа элементов |
Обратите внимание, что не существует присваивания массиву, соответствующего описанному выше способу инициализации.
int a[3] = {0, 1, 2}; |
// Объявление и инициализация |
a = {0, 1, 2}; |
// Ошибка |
Си. Примеры работы с одномерными массивами: ввод/вывод
В языке C нет возможности вводить и выводить весь массив одним оператором ввода/вывода. Можно вводить и выводить только один элемент массива. Следовательно, для того чтобы ввести весь массив, надо использовать цикл.
int a[10], n; printf("Введите количество элементов массива (от 0 до 9): "); |
// Объявляем массив и переменную для количества элементов массива |
scanf("%d", &n); |
// Ввод количества элементов массива |
if (n < 0 || n > 9) { printf("Количество элементов массива должно быть от 0 до 9!\n"); return; } |
// Если входные данные// то печатаем соответствующее сообщение и выходим из программы |
for (i = 0; i < n; i++) |
// Ввод массива по одному элементу |
scanf("%d", &a[i]); |
// Можно использовать scanf("%d", a + i) |
Вывод также осуществляется в цикле.
for (i = 0; i < n; i++) printf("a[%d] = %3d\n", i + 1, a[i]); |
|
В результате на экране мы увидим примерно следующий текст:
a[1] = 4
a[2] = 15
a[3] = -2
...
Си. Примеры работы с одномерными массивами: суммирование значений
Даны три массива разной размерности. Определить в каком массиве больше сумма элементов.
#include <cstdio> #include <locale.h>
const int nmax = 100; |
|
int ArrayInput(int *n, double x[], char *fname); |
// Функция ввода массива из файла |
double Sum(double x[], int n);
void main(int argc, char *argv[]) { double a[nmax], b[nmax], c[nmax]; double sa, sb, sc, max; int na, nb, nc;
setlocale(LC_ALL, "rus"); |
// Функция поиска суммы элементов массива
// Меняем кодировку для консольного приложения |
if (argc < 4) { printf("Недостаточно параметров!\n"); return; } if (!ArrayInput(&na, a, argv[1])) return; if (!ArrayInput(&nb, b, argv[2])) return; if (!ArrayInput(&nc, c, argv[3])) return;
sa = Sum(a, na); sb = Sum(b, nb); sc = Sum(c, nc);
max = sa; if (sb > max) max = sb; if (sc > max) max = sc;
if (sa == max) printf("Массив А имеет максимальную сумму элементов: %9.3lf\n", max); if (sb == max) printf("Массив B имеет максимальную сумму элементов: %9.3lf\n", max); if (sc == max) printf("Массив C имеет максимальную сумму элементов: %9.3lf\n", max); }
double Sum(double x[], int n) { double s = 0;
for (int i = 0; i < n; i++) s += x[i];
return s; }
int ArrayInput(int *n, double x[], char *fname) { FILE *file;
if ((file = fopen(fname, "r")) == NULL) { printf("Невозможно открыть файл '%s'\n", fname); return 0; } if (fscanf(file, "%d", n) < 1) { printf ("Ошибка чтения из файла '%s'\n", fname); fclose(file); return 0; } if (*n < 0 || *n > nmax) { printf("Кол-во эл-тов массива должно быть от 1 до %d! (файл '%s')\n", nmax, fname); return 0; } for (int i = 0; i < *n; i++) if (fscanf(file, "%lf", &x[i]) < 1) { printf ("Ошибка чтения из файла '%s'\n", fname); fclose(file); return 0; } fclose(file); return 1; } |
Си. Примеры работы с одномерными массивами: нахождение максимального элемента
#include <iostream>
using namespace std;
int main()
{
int m[10],I , min ,max;
for(i=0;i<10;i++){
cin>>m[i];
}
max=m[0];
for(i=1;i<10;i++){
if(max<m[i])max=m[i];
}
min=m[0];
for(i=1;i<10;i++){
if(min>m[i]) min = m[i];
}
cout<<"min = "<<min<<endl;
cout<<"max = "<<max;
system("PAUSE");
return 0;
}
Си. Примеры работы с одномерными массивами: циклический сдвиг
//Cдвигает элементы массива на 1 влево
#include <iostream>
#include <iterator>
#include <algorithm>
int main() {
std::size_t const arraySize = 10;
int array[arraySize] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::rotate(array, array + 1, array + arraySize);
std::copy(array, array + arraySize, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
Си. Примеры работы с одномерными массивами: поиск элемента
/* Бинарный поиск */
#include
main()
{
int k[100],v,i,j,m;
104
for (i=0;i<100;i++)
scanf("%d",&k[i]);
scanf("%d",&v);
i=0; j=100; m=50;
while (k[m]!=v)
{
if (k[m] < v) i+=m;
else j=m-i;
m=(i+j)/2;
}
printf("%d %d",v,m);
}
Си. Примеры работы с одномерными массивами: алгоритмы сортировки массивов
Сортировка выбором Идея метода состоит в том, чтобы создавать отсортированную последовательность путем присоединения к ней одного элемента за другим в правильном порядке. Если входная последовательность почти упорядочена, то сравнений будет столько же, значит алгоритм ведет себя неестественно.
template< class T >
void selectSort(T* arr, int size)
{
T tmp;
for(int i = 0; i < size; ++i) // i - номер текущего шага
{
int pos = i;
tmp = arr[i];
for(int j = i + 1; j < size; ++j) // цикл выбора наименьшегоэлемента
{
if (arr[j] < tmp)
{
pos = j;
tmp = arr[j];
}
}
arr[pos] = arr[i];
arr[i] = tmp; // меняем местами наименьший с a[i]
}
}
Сортировка пузырьком(обменом)
Идея метода: шаг сортировки состоит в проходе снизу вверх по массиву.По пути просматриваются пары соседних элементов. Если элементы некоторой пары находятся в неправильном порядке, то меняем их местами.
template< class T >
void bubbleSort(T* arr, int size)
{
T tmp;
for(int i = 0; i < size - 1; ++i) // i - номер прохода
{
for(int j = 0; j < size - 1; ++j) // внутренний цикл прохода
{
if (arr[j + 1] < arr[j])
{
tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
}
}
}
}
Сортировка вставками
Сортировка простыми вставками в чем-то похожа на вышеизложенные методы.
template< class T >
void insertSort(T* a, int size)
{
T tmp;
for (int i = 1, j; i < size; ++i) // цикл проходов, i - номер прохода
{
tmp = a[i];
for (j = i - 1; j >= 0 && a[j] > tmp; --j) // поиск места элемента в готовой последовательности
a[j + 1] = a[j]; // сдвигаем элемент направо, пока не дошли
a[j + 1] = tmp; // место найдено, вставить элемент
}
}
Сортировка Шелла Сортировка Шелла является довольно интересной модификацией алгоритма сортировки простыми вставками.
int increment(long inc[], long size)
{
int p1, p2, p3, s;
p1 = p2 = p3 = 1;
s = -1;
do
{
if (++s % 2)
{
inc[s] = 8*p1 - 6*p2 + 1;
}
else
{
inc[s] = 9*p1 - 9*p3 + 1;
p2 *= 2;
p3 *= 2;
}
p1 *= 2;
}
while(3*inc[s] < size);
return s > 0 ? --s : 0;
}
template< class T >
void shellSort(T a[], long size)
{
long inc, i, j, seq[40];
int s;
s = increment(seq, size); // вычисление последовательности приращений
while (s >= 0) // сортировка вставками с инкрементами inc[]
{
inc = seq[s--];
for (i = inc; i < size; ++i)
{
T temp = a[i];
for (j = i-inc; (j >= 0) && (a[j] > temp); j -= inc)
a[j + inc] = a[j];
a[j] = temp;
}
}
}
Пирамидальная сортировка
Пирамидальная сортировка является первым из рассматриваемых методов, быстродействие которых оценивается как O(n log n)
template< class T >
void downHeap(T a[], long k, long n)
{
// процедура просеивания следующего элемента
// До процедуры: a[k+1]...a[n] - пирамида
// После: a[k]...a[n] - пирамида
T new_elem;
long child;
new_elem = a[k];
while(k <= n/2) // пока у a[k] есть дети
{
child = 2*k;
if( child < n && a[child] < a[child+1] ) // выбираем большего сына
child++;
if( new_elem >= a[child] )
break;
// иначе
a[k] = a[child]; // переносим сына наверх
k = child;
}
a[k] = new_elem;
}
template< class T >
void heapSort(T a[], long size)
{
long i;
T temp;
// строим пирамиду
for(i = size / 2 - 1; i >= 0; --i)
downHeap(a, i, size-1);
// теперь a[0]...a[size-1] пирамида
for(i=size-1; i > 0; --i)
{
// меняем первый с последним
temp = a[i];
a[i] = a[0];
a[0] = temp;
// восстанавливаем пирамидальность a[0]...a[i-1]
downHeap(a, 0, i-1);
}
}
Си. Символьные строки: объявление символьных строк
Объявить строку = выделить ей место в памяти и присвоить имя.
char s[80]; //выделяется 80 байт, в строке – «мусор» )
char s1[80] = "abc"; //выделяется 80 байт, занято 4 байта (с учетом '\0')
char qqq[] = «Руслан"; // выделяется 7 байт
(с учетом '\0')
Задача: ввести слово с клавиатуры и заменить все буквы «а» на буквы «б».
main()
{
char q[80];
int i;
printf("Введите строку\n");
scanf( "%s", q);
i = 0;
while ( q[i] != '\0' ) {
if ( q[i] == 'а' ) q[i] = 'б';
i ++;
}
printf ( "Результат: %s ", q );
}
Си. Символьные строки: функции для работы со строками
Таблица 1 — Функции для работы со строками и символами | |
Функция |
Пояснение |
strlen(имя_строки) |
определяет длину указанной строки, без учёта нуль-символа |
Копирование строк | |
strcpy(s1,s2) |
выполняет побайтное копирование символов из строки s2 в строку s1 |
strncpy(s1,s2, n) |
выполняет побайтное копирование n символов из строки s2 в строку s1. возвращает значения s1 |
Конкатенация строк | |
strcat(s1,s2) |
объединяет строку s2 со строкой s1. Результат сохраняется в s1 |
strncat(s1,s2,n) |
объединяет n символов строки s2 со строкой s1. Результат сохраняется в s1 |
Сравнение строк | |
strcmp(s1,s2) |
сравнивает строку s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 — если s1>s2 С учётом регистра |
strncmp(s1,s2) |
сравнивает n символов строки s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 — если s1>s2 С учётом регистра |
stricmp(s1,s2) |
сравнивает строку s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 — если s1>s2 Без учёта регистра |
strnicmp(s1,s2) |
сравнивает n символов строки s1 со строкой s2 и возвращает результат типа int: 0 –если строки эквивалентны, >0 – если s1<s2, <0 — если s1>s2 Без учёта регистра |
Обработка символов | |
isalnum(c) |
возвращает значение true, если с является буквой или цифрой, и false в других случаях |
isalpha(c) |
возвращает значение true, если с является буквой, и false в других случаях |
isdigit(c) |
возвращает значение true, если с является цифрой, и false в других случаях |
islower(c) |
возвращает значение true, если с является буквой нижнего регистра, и false в других случаях |
isupper(c) |
возвращает значение true, если с является буквой верхнего регистра, и false в других случаях |
isspace(c) |
возвращает значение true, если с является пробелом, и false в других случаях |
toupper(c) |
если символ с, является символом нижнего регистра, то функция возвращает преобразованный символ с в верхнем регистре, иначе символ возвращается без изменений. |
Функции поиска | |
strchr(s,c) |
поиск первого вхождения символа с в строке s. В случае удачного поиска возвращает указатель на место первого вхождения символа с. Если символ не найден, то возвращается ноль. |
strcspn(s1,s2) |
определяет длину начального сегмента строки s1, содержащего те символы, которые не входят в строку s2 |
strspn(s1,s2) |
возвращает длину начального сегмента строки s1, содержащего только те символы, которые входят в строку s2 |
strprbk(s1,s2) |
Возвращает указатель первого вхождения любого символа строки s2 в строке s1 |
Функции преобразования | |
atof(s1) |
преобразует строку s1 в тип double |
atoi(s1) |
преобразует строку s1 в тип int |
atol(s1) |
преобразует строку s1 в тип long int |
Функции стандартной библиотеки ввода/вывода <stdio> | |
getchar(с) |
считывает символ с со стандартного потока ввода, возвращает символ в формате int |
gets(s) |
считывает поток символов со стандартного устройства ввода в строку s до тех пор, пока не будет нажата клавиша ENTER |
Си. Указатели: описание, инициализация, операции с указателями
Си. Структуры. Массивы структур
Структура – это сложный тип данных представляющий собой упорядоченное в памяти множество элементов различного типа. Каждый элемент в структуре имеет свое имя и называется полем. В СИ элементы структуре располагаются последовательно, а размер структуры определяется суммой размеров всех элементов. Объявление в СИ структуры имеет вид: struct [имя типа] { поле_1; поле_2; ... поле_N; } [список переменных]; Объявление полей структуры возможно только без инициализации. Если несколько полей следующих друг за другом в описании структуры имеют один и тот же тип, то для их описания можно использовать синтаксис объявления нескольких переменных одного и того же типа. Типом поля может быть любой тип (как системный, так и пользовательский), описанный ранее. Примеры структур: Пример структуры в СИ, содержащая информацию о точке в двумерном пространстве (координаты): struct Point { double x, y; }; А вот структура в СИ, содержащая информацию об окружности: struct Circle { double x, y, r; }; Структура, содержащая информацию о студенте (фамилия, имя, отчество, номер зачетной книжки, средний балл): struct Student { char sname[20], name[20], patronymic[20]; unsigned int num; double mark; }; Структура в СИ, содержащая информацию о группе студентов (название группы, количество студентов, список студентов (максимально 30)): struct Group { char name[10]; unsigned number; struct Student list[30]; };
Си. Организация линейных списков