Опубликован: 25.08.2010 | Доступ: свободный | Студентов: 6095 / 596 | Оценка: 3.91 / 3.44 | Длительность: 11:09:00
Лекция 3:

Управляющие операторы. Структуры данных языка С

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >

Массивы

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

Конечная именованная последовательность однотипных величин называется массивом.

В С++ различают массивы фиксированного размера и массивы переменного размера ( динамические ). Количество элементов в массиве первого типа известно при написании программы и никогда не меняется. Память под такой массив выделяет компилятор. Количество элементов динамического массива на этапе компиляции не известно и, как правило, зависит от входных данных. Память под динамический массив выделяется во время выполнения программы с помощью операций выделения памяти.

Описание массива фиксированного размера отличается от описания простой переменной наличием после имени квадратных скобок, в которых задается количество элементов массива ( размерность ):

float a [10]; 	//Пример описания массива из 10 вещественных чисел

Тип элементов массива - любой допустимый тип С++, например, встроенный или библиотечный, кроме типа void. Элементы массива нумеруются с нуля. Глобальный массив по умолчанию инициализируется нулями. Локальный массив, как и обычная переменная, по умолчанию никак не инициализируется. Инициализирующие значения при желании задают в фигурных скобках:

int b[5] = {3, 2, 1};	// b[0]=3, b[1]=2, b[2]=1, b[3]=0, b[4]=0

Размерность массива может быть задана только целой положительной константой или константным выражением.

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

#include <iostream>
using namespace std;
int main(){
	const int n = 10;
	int marks[n] = {3, 4, 5, 4, 4};
	for (int i = 0, sum = 0; i<n; i++) sum += marks[i];
	cout << "Сумма элементов: " << sum;}

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

Динамические массивы создают с помощью операции new, при этом необходимо указать тип и размерность, например:

float *p = new float [100];

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

Преимущество динамических массивов состоит в том, что их размерность может не быть константой.

Память, зарезервированная под динамический массив с помощью new [], должна освобождаться оператором delete [], а память, выделенная функцией malloc - посредством функции free, например:

delete [] p; free (q);

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

float *p = new float [n]();

Многомерные массивы фиксированного размера задаются указанием каждого измерения в квадратных скобках, например, оператор

int matr [6][8];

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

Для доступа к элементу многомерного массива указываются все его индексы, например, matr[i][j].

Инициализация многомерного массива:

int mass2 [][] = { {1, 1}, {0, 2}, {1, 0} };
int mass2 [3][2] = {1, 1, 0, 2, 1, 0};

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

matr = new int [a] [b];

Освобождение памяти из-под массива с любым количеством измерений выполняется с помощью операции delete []. Указатель на константу удалить нельзя.

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

#include <сstdio>
#include <iomanip>
using namespace std;
int main()
{
const int nstr = 4, nstb = 5;    // размерности массива
int b[nstr][nstb];               // описание массива
int i, j;    
for ( i = 0; i < nstr; i++ )  // ввод массива
  for ( j = 0; j < nstb; j++ ) 
    scanf( "%d", &b[i][j] );
int istr = -1, MaxKol = 0;
for ( i = 0; i < nstr; i++ )  // просмотр массива по строкам
  {
  int Kol = 0;
  for ( j = 0; j < nstb; j++ ) 
    if (b[i][j] == 0) Kol++;    
  if ( Kol > MaxKol )
    { istr = i; MaxKol = Kol; }
  } printf( " Исходный массив:\n" );
for ( i = 0; i < nstr; i++ )
  {
  for ( j = 0; j < nstb; j++ ) 
    printf( "%d ", b[i][j] );
  printf( "\n" );
  }
if ( istr == -1 ) printf( "Нулевых элементов нет" );
  else printf( "Номер строки: %d", istr ); 
}

Создание и обработка динамических многомерных массивов иллюстрируется примером умножения двух квадратных матриц:

#include <iostream>
using namespace std;
int main()
{   
int i, j, n; 
cout << "Введите размеры матриц А, B, R "; 
cin >> n;
// выделение памяти под матрицы
float **a = new float*[n];   // указатель на матрицу А
for( j = 0; j < n; j++ ) 
  a[j] = new float [n];
float **b = new float*[n];   // указатель на матрицу В
for( j = 0; j < n; j++ ) 
  b[j] = new float [n];              
float **r = new float*[n];   // указатель на матрицу R          
for( j = 0; j < n; j++ ) 
  r[j] = new float [n];
// ввод матриц А и В
for ( i = 0; i < n; i++ )
  {   
  for ( j = 0; j < n; j++ ) 
    cin >> a[i][j]; 
    cout << endl; 
  }  
cout << endl;    
for ( i = 0; i < n; i++ )
  {
  for ( j = 0; j < n; j++ ) 
  cin >> b[i][j]; 
  cout << endl; 
  }
cout << endl;    
for ( i = 0; i < n; i++ )  // умножение матриц
  for ( j = 0; j < n; j++ )
    {
    float s = 0;
    for ( int k = 0; k < n; k++ ) 
      s += a[i][k] * b[k][j];
    r[i][j] = s; 
    }
cout << "Ответ" << endl; // вывод на экран матрицы-результата
for ( i = 0; i < n; i++ )
  {
  for ( j = 0; j < n; j++ ) 
    cout <<setw(6) << r[i][j]; 
  cout << endl;  
  }
// уничтожение динамических массивов
for ( i = 0; i < n; i++ ) delete[] a[i]; delete[]a;
for ( i = 0; i < n; i++ ) delete[] b[i]; delete[]b;
for ( i = 0; i < n; i++ ) delete[] r[i]; delete[]r;
}

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

Строки

Строка представляет собой массив символов, заканчивающийся нуль-символом. Нуль-символ - это символ с кодом, равным 0, что записывается в виде управляющей последовательности '\0'. По положению нуль-символа определяется фактическая длина строки. Строку можно инициализировать строковым литералом:

char str[10] = "Vasia";

В этом примере под строку выделяется 10 байт, 5 из которых занято под символы строки, а шестой - под нуль-символ. Если строка при определении инициализируется, ее размерность можно опускать (компилятор сам выделит соответствующее количество байт):

char str[] = "Vasia";	//Выделено и заполнено 6 байт

Оператор

char *str = "Vasia"

создает не строковую переменную, а указатель на строковую константу.

Операция присваивания одной строки другой не определена и может выполняться с помощью цикла или функций стандартной библиотеки.

Для работы со строками С нужно подключить к программе заголовочный файл <cstring>. Ввод и вывод С-строк обеспечивает библиотека ввода-вывода <cstdio>.

Стандартная библиотека предоставляет возможности копирования, сравнения, объединения строк, поиска подстроки, определения длины строки и т.д., а также содержит специальные функции ввода строк и отдельных символов с клавиатуры и из файла.

Пример (программа запрашивает пароль не более трех раз):

#include <cstdio>  // библиотека ввода-вывода
#include <cstring> // библиотека для работы со строками старого стиля
#include <clocale> // библиотека локализации
using namespace std;
int main()
{   
setlocale( LC_ALL, "rus" );
char s[5], 
     passw[] = "kuku";  // passw - эталонный пароль
bool ok = false;
for ( int i = 0; ! ok && i < 3; ++i )
  {
  printf( "\nвведите пароль (4 символа):\n" );
  gets( s );                      // ввод строки c клавиатуры
  if ( strcmp( s, passw ) == 0 ) 
    ok = true;         // сравнение строк
  }
if ( ok ) 
  printf( "\nпароль принят\n" );
  else      printf( "\nпароль не принят\n" );
}

ПРИМЕЧАНИЕ

Библиотечные функции работы со строками С объявлены в стандарте устаревшими, так как они не обеспечивают необходимой безопасности. Например, если в приведенную выше программу ввести строку, превышающую 4 символа, программа может завершиться аварийно.

При работе со строками часто используются указатели. Для примера рассмотрим копирование строки src в строку dest:

#include <iostream>
using namespace std;
int main()
{   char src[10]; 
    cin >> src;            // ввод строки до первого пробела
    char *dest = new char [10], 
		 *d = dest, *s = src;
    while ( *d++ = *s++ );       // копирование строки
    cout << dest;                             
}
< Лекция 2 || Лекция 3: 12345 || Лекция 4 >
Dana Kanatkyzi
Dana Kanatkyzi
Здравствуйте.Помогите решить задачу минимум 4 чисел.Условие такое:"Напишите функцию int min (int a, int b, int c, int d) (C/C++)"находящую наименьшее из четырех данных чисел."Заранее спасибо!
Юрий Семевский
Юрий Семевский
Россия, Санкт-Петербург
Александр Богдашов
Александр Богдашов
Россия