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]


 

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

36088. Господарське право: Курс лекцій 3.56 MB
  У пропонованому курсі лекцій на підставі аналізу нормативно-правових актів. Висвітлюються основні теми та інститути господарського права - як загальної частини (поняття господарського права, господарські правовідносини, господарське законодавство, субєкти господарських правовідносин, майнова основа господарювання
36089. ИСТОРИЯ ПЕДАГОГИКИ 2.42 MB
  Плохова История педагогики: Учебник для системы послевузовского профессионального образования по специальности История и философии науки Под редакцией члена корреспондента РАО М. Предлагаемое издание составлено в соответствии с программой История и философия науки раздел История педагогики одобренной экспертными советами ВАК Министерства образования и науки РФ по педагогике и психологии и по истории и предназначено для подготовки к сдаче кандидатского экзамена по педагогике. Она занята критической интерпретацией истории...
36090. Організація навчального процесу у вищих закладах освіти 258.5 KB
  Б79 Організація навчального процесу у вищих закладах освіти: Навч. посібник для слухачів закладів підвищення кваліфікації системи вищої освіти. ISBN 9667170063 У посібнику розглядаються питання організації навчального процесу у вищих закладах освіти України відповідно до Положення про організацію навчального процесу у вищих навчальних закладах затвердженого наказом Міністерства освіти України від 2 червня 1993 року № 161 та інших нормативних актів з питань вищої освіти. Розрахований на слухачів закладів підвищення кваліфікації...
36091. ПОРІВНЯЛЬНА ПЕДАГОГІКА 397.5 KB
  Розвиток освіти на сучасному етапі Б. Обєктом дослідження порівняльної педагогіки є розвиток освіти на глобальному світовому регіональному окремих материків частин світу та локальному окремих держав національному частин держав етнічному рівнях в її минулому сучасному та майбутньому аспектах.; стан основні тенденції та закономірності розвитку освіти в різних країнах геополітичних регіонах і в глобальному масштабі; співвідношення загальних тенденцій і національної або регіональної специфіки позитивні й негативні аспекти...
36092. Історія держави та права 909.5 KB
  Предмет і завдання курсу історії держави і права зарубіжних країн. Значення історії держави і права як науки та її місце її в системі юридичних дисциплін. Періодизація історії держави і права зарубіжних країн. Виникнення держави і права.
36093. Опорний конспект лекцій з «Основ економічних теорій» 528.5 KB
  Представники цієї теорії вважали що країна зміцнює своє економічне становище якщо вона активно продає за кордон товари власного виробництва експортує але при цьому обмежує або забороняє ввіз товарів закордонного виробництва імпорт. Монкретьєн запровадив термін політекономія поліс держава що означає державне управління господарством таким словом він відобразив активне втручання держави в економіку в період формування капіталістичного способу виробництва. Класики встановили що багатство створюється саме в сфері виробництва....
36094. ФІНАНСОВИЙ МЕНЕДЖМЕНТ. КОНСПЕКТ ЛЕКЦІЙ 2.58 MB
  03050401 Економіка підприємства і 7.03050401 Економіка підприємства ОКР Магістр Мелітополь 2011 УДК Фінансовий менеджмент.03050401 Економіка підприємства і 7.03050401 Економіка підприємства ОКР Магістр.
36095. Історія України. Опорний конспект лекцій, І.М. Гавриленко 1.7 MB
  Первісна історія України. Населення України І тис. Директорія у боротьбі за незалежність україни. Попри різні політичні впливи наука займається відшукуванням об’єктивної істини в її багатогранності. Важливе значення має методологія досліджень, тобто сукупність методів, які застосовуються дослідниками. Для досягнення творчих завдань історики використовують загальнонаукові (наприклад, метод класифікації), специфічно-історичні (хронологічний, описовий, порівняльний тощо) та міждисциплінарні (статистичний, математичний і т. д.) методи.
36096. Інвестиційне проектування. Курс лекцій 1.62 MB
  Оцінка економічної привабливості та ефективності проекту [0. Методичні підходи до визначення економічної вартості проекту [0. Оцінка впливу проекту на економіку країни ТЕМА 1. Досвід проектування на всіх його стадіях накопичений за умов адміністративної економіки базувався на принципах і методах адміністративнокомандної системи і був відірваний від сучасної методології й багатющого інструментарію що застосовується у світовій економічній науці.