85889

Указатели. Одномерные массивы и в языке программирования Си++

Лабораторная работа

Информатика, кибернетика и программирование

Цель работы: Освоить работу с указателями и операциями над указателями ознакомиться с основными принципами работы с одномерными массивами 1. Существует следующие способы инициализации указателя: Присваивание указателю адреса существующего объекта: С помощью операции получения адреса например...

Русский

2015-03-31

169 KB

3 чел.

Лабораторная работа №4

“ Указатели. Одномерные массивы и в языке программирования Си++”

  1.  Теоретические сведения

Цель работы: Освоить работу с указателями и операциями над указателями, ознакомиться с основными принципами работы с одномерными массивами

1.1. Указатели. С++ и его предок С- это языки программирования , которые используются так же для программирования систем на низком уровне / даже некоторые программисты считают С языком ассемблера высокого уровня/. В программировании систем на низком уровне часто приходится работать с адресами данных и здесь начинаются  необходимость использования указателей.

Что такое указатель? В физическом смысле каждая частица информации /это может быть код или данные и т.п./ в компьютерной памяти находится по определенному адресу и занимает определенное количество байт. При выполнении программы каждая переменная программы  имеет определенный адрес в памяти компьютера. При работе с языками высокого уровня /например, С++, Паскаль ,Бейсик и т.д./ программист не интересуется с истинными адресами  переменных , так как эти задачи невидимым образом для нас решается компилятором или средой программирования.  Идентификатор переменной в программе логически выполняет роль этикетки на ящике, т.е. адреса ячейки памяти.

Адрес –это местоположение ячейки памяти. Этикетка адреса –это имя переменной.

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

Таким образом можно сказать, что указатель – это специальная переменная, которая хранит адрес другой переменной, другого объекта или иной информации. Так как указатель – это адрес определенного  объекта, то есть  через него можно обращаться к данному объекту.

Указатель не является самостоятельным типом, он всегда связан с каким либо другим конкретным типом /например, int, float, double или массив, функция  т.п./.

В  языке программирования С++ различают три вида указателей:  указатели на объект, указатель на функцию, указатель на  void. / указатель на функцию, указатель на  void рассматривается позже/

Общий формат объявления указателя на объект:

                                                         тип  <*имя_указателя> ;  

здесь тип – это название типа, *- унарная операция обращения по адресу / или операция разыменования, операция доступа по адресу, операция раскрытия ссылки и т.д./, имя_указателя – идентификатор переменной. Например:

                                                              int *ukaz_a;

Унарная операция «звездочка» или * - непосредственно относится к имени, поэтому при объявлении нескольких указателей ,требуется  ставить ее перед именем каждого из них. Например:

                                                              int *ukaz_a, *ukaz_b, *ukaz_c   ;

Операции с указателями.  

  1.  *- унарная операция обращения по адресу / или операция разыменования, операция доступа по адресу, операция раскрытия ссылки, операция разадресации/ предназначена для доступа к величине , адрес которой хранится в указателе;
  2.  присваивание :

                                 char *ukaz_ch=’ю’;

  1.  операция приведение типов /Подбельский, 117 стр./:  

   unsigned long L=0x12345678L;

   char *ukaz_ch=(char *)&L; //приведение типа long  к типу char*

   int *ukaz_int=(int *)&L; // приведение типа long  к типу int *

                                  

  1.  Операции инкремент (++) и декремент (--):  *ukaz_int ++    или  *ukaz_int --    
  2.  & -унарная операция получения адреса /или операция взятия адреса/, предназначена к величинам имеющим имя и размещенным  в оперативной памяти, т.е . это означает, что нельзя получить адрес скалярного выражения, неименованной константы и т.д.

int a=45; // объявление переменной а

 int *ukaz_a=&a; // объявление указателя для переменной а и получение адреса переменной a

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

  1.  Присваивание указателю адреса существующего объекта:
    •  С помощью операции получения адреса, например:

int a=45; // существующий объект –объявленная  переменная-  а

                     int *ukaz_a=&a;

                    int *ukaz_a (&a);

  •  С помощью значения другого инициализированного указателя, например:

int a=45;

                      int *ukaz_a=&a; // инициализированный указатель

              int *ukaz_a2= ukaz_a;

  •  С помощью имени массива или функции /имя массива или функции считается как адрес/, например:  

 int  massiv[10]; // объявление массива

int *ukaz_mas=massiv; // присваивание  адреса начала массива или имени массива

…         …    

void  funk(int arg1, int arg2); // объявление функции

void  (*ukaz_funk) (int); // объявление указателя на функцию

ukaz_funk= funk; // присваивание  адреса функцции

 

  1.  Присваивание указателю пустого или нулевого значения, например:    int *ukaz1=NULL; или    int *ukaz2=0;  

  1.  Присваивание указателю адреса области памяти в явном виде, например:

char  *ukaz_adr=(char *) 0xB8000000;

здесь,   0xB8000000- шестнадцатеричная константа, (char *)- операция приведения типа, т.е. константа преобразуется к типу  «указатель на char » ;

Применение указателей.  Указатели чаще всего  используются при работе с динамической памятью, иногда называемой «кучей» / куча в переводе с английского означает heap/.  Динамическая  память –это свободная память, в которой можно во время выполнения программы выделять место в соответствии с потребностями. Доступ к выделенным участкам динамической памяти , так называемым динамическими переменными производится только через указатели. Время жизни динамических переменных  от точки их  создания и до конца выполнения программы или до явного освобождения памяти. Для работы с динамической памятью в С++ чаще всего  используются две  операции  new /выделяет место в памяти/  и delete /освобождает или вернет  место в памяти выделенной операцией new/  . Например:

int *n= new int; // операция new выполняет выделение достаточного для размещения величины типа int участка  

                            динамической памяти и  записывает адрес начала этого участка в переменную  n.

int *m= new int(10); // выделение участка под int , записывает адрес начала этого участка в переменную  m и

                                     производится иницализация динамической переменной значением 10.

int *massiv= new int[10]; // // операция new выполняет выделение памяти под 10 величин  типа int  /или массива из 10 элементов/  и  записывает адрес начала этого участка в переменную  massiv, к оторая может считаться как имя массива.

delete n; //освобождение выделенного участка памяти для n или уничтожение динамической переменной n

delete m; // освобождение выделенного участка памяти для m или уничтожение динамической переменной m

delete massiv;// освобождение выделенного участка памяти или уничтожение динамического массива massiv

Пример1:

#include "iostream.h"

#include "conio.h"

#pragma argsused

int main()

{

 int a=45; // объявление переменной а

 int *ukaz_a=&a; // объявление и иницализация указателя для переменной а

 cout<<"\n a="<<a;

 cout<<"\n ukaz_a="<<*ukaz_a;

 getch();

       //return 0;

}

РЕЗУЛЬТАТ ПРОГРАММЫ:

1.2. Массивы

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

Массивы объявляются так же, как и переменные. Например:

int a[100];

float c[10][20];

В первой строке объявляем массив а из 100 элементов целого типа: а[0],a[1], … ,a[99] (индексация всегда начинается с нуля). Во второй строке объявлен двумерный массив вещественного типа. Двумерный массив представляется как одномерный, элементы которого являются тоже массивами. В первых квадратных скобках указывается количество строк в массиве, во вторых – количество столбцов.

Пример 1. Задан одномерный массив S, состоящий из десяти элементов вещественного типа. Вывести на экран дисплея значения элементов этого массива в обратном порядке.

#include "stdio.h"

#include "conio.h"

#include "iostream.h"

main()

{

float s[10];

int i;

for (i=0; i<10;i++)

scanf("%f", &s[i]); /*ввод элементов массива*/

for (i=9; i>=0;i--)

printf("%f", s[i]); /* вывод элементов в обратном порядке*/

getch();

return 0;

}

В заключении этого раздела отметим, что массив можно инициализировать, т.е. присвоить его элементам начальные значения. Это делается при объявлении типа массива, например:

int a[5]= { 0, 0, 0, 0, 0};

Это значит, что все элементы массива получают нулевое значение.

При инициализации число элементов можно не указывать, т.к. в этом случае оно может быть вычислено по количеству присваиваемых значений (в фигурных скобках), например:

int a[] = {10,20,30,40,50};

1.3.  Указатели и одномерные массивы

В С++ существует тесная связь между указателями и массивами. Любой доступ к элементу массива, осуществляемый операцией индексирования, может быть выполнен при помощи указателя.

Объявление

int a[10];

определяет массив а размера 10, т.е. блок из десяти последовательных объектов, представленных на рисунке, с именами a[0], a[1], … ,a[9].

Запись a[i] отсылает нас к i-му элементу массива. Если ра есть указатель, т.е. определен как

int *pa; , то в результате присваивания    pa = &a[0];

pa будет указывать на нулевой элемент массива а; иначе говоря, ра будет содержать адрес элемента a[0] (см. рис.). Теперь присваивание

x=*pa;

будет копировать содержимое а[0] в х.

Если ра указывает на некоторый элемент массива, то ра+1 по определению указывает на следующий элемент (см. рис.).Таким образом, если ра указывает на a[0], то *(ра+1) есть содержимое a[1], ра+1 – адрес a[1], *(ра+i) – содержимое a[i].

Поскольку имя массива есть не что иное как адрес его начального элемента, присваивание

pa=&a[0];

можно также записать в следующем виде:

pa = a;

Так как ра – указатель , то в выражениях его можно использовать с индексом, то есть запись pa[i] эквивалентна записи *(pa+i). Элемент массива одинаково разрешается изображать и в виде указателя со смещением, и в виде имени массива с индексом.

Между именем массива и указателем, выступающим в роли имени массива, существует одно различие. Указатель – это переменная, поэтому можно написать pa=a или pa++. Но имя массива не является переменной, и запись типа a=pa не допускается.

Следует также различать выражения *(a+2) и *a+2:

*(а+2) – значение третьего элемента массива а;

*а+2 – добавление числа 2 к значению первого элемента массива.

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

#include "stdio.h"

#include "conio.h"

#include "iostream.h"

int a[6]={10,20,30,40,50,60};

main()

{

int  i, *p;

/*объявление и инициализация массива*/

for (i=0;i<6;i++)

printf("%d",a[i]); /*вывод массива обычным способом*/

printf("\n");

p=a;

for (p=&a[0];p<=&a[5];p++)

printf("%d", *p); /*вывод массива с использованием указателя*/

printf("\n");

for (p=&a[0],i=0;i<6;i++)

printf("%d", p[i]); /*еще один вариант с использованием указателя*/

getch();

return 0;

}

Дадим еще некоторые пояснения. Операция р++ увеличивает значение указателя на единицу. Если p=&a[i], то после операции р++ в р содержится адрес элемента a[i+1].

Пример 3. Найти среднее арифметическое массива, состоящего из шести элементов, с использованием указателя.

#include "stdio.h"

#include "conio.h"

#include "iostream.h"

int a[]={10,20,30,40,50,60};

main()

{

int  i, *p;

float s;

p=a; /*указатель получает значение адреса нулевого элемента массива*/

for (s=0,i=0;i<6;i++)

s+=*(p+i); /*получение суммы элементов массива*/

s=s/6; /*среднее арифметическое массива*/

printf("%f", s);

getch();

return 0;

}

Пример 4. Решить задачу, приведенную в примере 1, с использованием указателя.

#include "stdio.h"

#include "conio.h"

#include "iostream.h"

main()

{

int s[10];

int *p, i;

for (i=0; i<10;i++)

scanf("%d", &s[i]);

p=&s[9]; /*указатель получает значение адреса последнего элемента массива*/

for (i=0; i<10;i++)

printf ("%d",*(p-i)); /*вывод элементов в обратном порядке*/

for (p=&s[9];p>=&s[0];p--)/*еще один способ вывода элементов в обратном порядке*/

printf("\n%d", *p);

getch();

return 0;

}

Пример5. Сортировать массив из 10 целых чисел по убыванию методом прямого выбора.

#include<conio.h>

#include<stdlib.h>

 #include<time.h>

#pragma argsused

void main()

{   int massiv[10];

int i,j,k, max,Nmax,bufPerem;

time_t t;

srand ((unsigned)time(&t)); //иниццализация генератора случайных чисел

// формирование массива

for (i=0; i<=9; i++)

{

massiv[i]=rand()%19+2; //присваивание элементу массива случайного значения которое выдает  функция  rand

cout<<"\t" <<massiv[i];

}

//сортировка массива

for (i=0; i<=9; i++)

{ max=massiv[i]; Nmax=i;

 for (j=i+1; j<=9; j++)

 if (max<massiv[j])

{

max= massiv[j]; Nmax=j;

} ;

bufPerem=massiv[i];

massiv[i]=max;

massiv[Nmax]=bufPerem;

//вывод промежуточного состояния массива

/*cout<<"\n "<<i<<"- shag  :";

 for (k=0; k<=9; k++)

cout<<"\t" <<massiv[k];*/

}

// вывод  отсортированного массива

cout<<"\n ";

 for (i=0; i<=9; i++)

cout<<"\t" <<massiv[i];

getch();

       //return 0;

}

2. Задание

Задание взять из таблицы согласно заданному варианту. Написать два варианта программы: без применения указателей и с указателями.

Массив

Действия

Условия и ограничения

1.

X(N)

Вычислить сумму и количество элементов Х

0<=Xi, N<100  

2.

A(80)

Вычислить среднее арифметическое значение элемента массива А

Ai >0

3.

X(70)

Переписать элементы массива Х в массив Y и подсчитать их количество

-1<=Xi <=1

4.

B(50)

Определить максимальный элемент массива В и его порядковый номер

Bi>0

5.

C(40)

Определить минимальный элемент массива С и его порядковый номер

Ci <0

6.

D(80)

Найти максимальный и минимальный элемент массива и поменять их местами

7.

Y(20)

Вычислить среднее геометрическое элементов массива

Yi >0

8.

Z(30)

Расположить в массиве R сначала положительный а затем отрицательный элементы массива Z

9.

N(50)

Определить сумму элементов массива N кратных трем

INT(Ni/3)*3=Ni

10.

X(N)

Вычислить сумму и количество элементов массива Х

Xi>0,N<=30

11.

X(N)

Вычислить среднее геометрическое элементов массива

Xi>0,N<=50

12.

X(N)

Переписать в массив Y подряд положительные элементы массива Х

Xi>0,N<=40

13.

X(N)

Переписать в массив Y положительные элементы а в массив Z отрицательные элементы массива Х

N<=40

14.

B(K)

Определить максимальный элемент массива В и его порядковый номер

Xi>0,K<=40

15.

С(К)

Определить минимальный элемент массива С и его порядковый номер

-1<=Xi<=1,

K<=20

6

PAGE  5


Ра

a+1

Pa+2

a:

a[0]

a[1]

a[9]


 

А также другие работы, которые могут Вас заинтересовать

24217. Важнейшие факторы экономического роста предприятия 44 KB
  Сущность и основные факторы экономического роста предприятия; 2. Показатели эффективности деятельности предприятия и методика их расчета; 3. Экономический рост тенденция изменения совокупных показателей развития предприятия за определенный промежуток времени обычно за год.
24218. Трудовые ресурсы и производительность труда. Организация, нормирование и оплата труда 66 KB
  Отличие трудовых ресурсов от других видов ресурсов в том, что каждый наемный работник может отказаться от предложенных ему условий и потребовать изменения условий труда, переобучения, уволиться по собственному желанию.
24219. Экономическая сущность основных фондов 72.5 KB
  Кроме основных производственных фондов в состав основных фондов промышленности входят и основные непроизводственные фонды. В практике учета и планирования воспроизводства основных фондов промышленности используются как денежные так и натуральные показатели поскольку основные фонды в производственном процессе выступают не только как носители стоимости но и как совокупность определенных средств труда. Денежная оценка основных фондов необходима для учета их динамики планирования расширенного воспроизводства установления снашиваемости...
24220. Источники формирования собственных оборотных средств предприятия 52 KB
  Деление оборотных средств на оборотные производственные фонды и фонды обращения определяется особенностями их использования и распределения в сферах производства продукции и ее реализации. Оборотные средства обслуживающие процесс обращения продукции представляют собой фонды обращения. Расходы будущих периодов это невещественные элементы оборотных фондов включающие затраты на подготовку и освоение новой продукции которые производятся в данном периоде квартал год но относятся на продукцию будущего периода например затраты на...
24221. Компетенция преподавателя 34 KB
  В общении необходимо проявлять активность которая в свою очередь вызывается следующими способами: 1 интересная тема 2 актуальные для возраста темы 3 личностнозначимые темы 4 интересное задание 5 разнообразное задание 6 система поощрений и наказаний. специфика среднего этапа: большие трудности с возрастом учащихся личностнозначимые темы играют гораздо большую роль преподаватель должен быть очень осторожен в подборе тем большое колво речевых упражнений 3.
24223. Речевая деятельность в школе 72.5 KB
  Научить учащихся понимать звучащую речь одна из важнейших целей обучения. Структура письма как и говорения состоит из 3х частей: 1 побудительномотивационная появляется мотив потребн6ость вступить в общение чтото передать письменно сообщить инфу возникает замысел высказывания; 2 аналитикосинтетическая формируется и реализуется само высказывание: отбор слов распределение предметных признаков в группе предложения смысловая организация связей между предложениями; 3 исполнительная фиксация продукта с помощью графических...
24225. Содержание обучения ин. Яз., его основные компоненты 30 KB
  Цель: ознакомиться с общим содержанием текста газеты библиотечный материал. Цель: изучить содержание текста с целью его дальнейшего применения извлекается до 80 инф. Цель: проанализировать тщательно содержание текста извлекается до 100. В зарубежной методике:1 scheming наше ознакомительное чтение2 scanning поисковое чтение3 reading for detail Аналитическое и Изучающее чтение Критерии отбора текстов: 1 объем текста 2 тематичность 3 тема урока 4 интересная тема 5 возможность обсуждения 6 проблематика проблематика в тексте...