Главная

Популярная публикация

Научная публикация

Случайная публикация

Обратная связь

ТОР 5 статей:

Методические подходы к анализу финансового состояния предприятия

Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века

Ценовые и неценовые факторы

Характеристика шлифовальных кругов и ее маркировка

Служебные части речи. Предлог. Союз. Частицы

КАТЕГОРИИ:






Указатели и массивы. 1. Напишите программу, которая принимает группу чисел от пользователя и помещает их в массив типа float

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

Указатели и массивы

Указатели и массивы

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

// lab9_1.cpp

// finds average of numbers typed by user

#include <iostream>

using namespace std;

 

int main()

{

float flarr[100]; //array for numbers

char ch; //user decision

int num = 0; //counts numbers input

do

{

cout << "Enter number: "; //get numbers from user

cin >> *(flarr+num++); //until user answers 'n'

cout << " Enter another (y/n)? ";

cin >> ch;

}

while(ch!= 'n');

 

float total = 0.0; //total starts at 0

for(int k=0; k<num; k++) //add numbers to total

total += *(flarr+k);

float average = total / num; //find and display average

cout << "Average is " << average << endl;

return 0;

}

 

2. Используйте класс String, который приведён ниже. Добавьте к нему метод upit(), который будет переводить символы строки в верхний регистр. Вы можете использовать библиотечную функцию toupper(), которая принимает отдельный символ в качестве аргумента и возвращает символ, переведенный в верхний регистр (если это необходимо). Эта функция использует заголовочный файл Cctype. Добавьте в функцию main() необходимые строки для тестирования метода upit().

// lab9_2.cpp

// member function converts String objects to upper case

#include <iostream>

#include <cstring> //for strcpy(), etc

#include <cctype> //for toupper()

using namespace std;

////////////////////////////////////////////////////////////////

class String //user-defined string type

{

private:

char* str; //pointer to string

public:

String(char* s) //constructor, one arg

{

int length = strlen(s); //length of string argument

str = new char[length+1]; //get memory

strcpy(str, s); //copy argument to it

}

~String() //destructor

{ delete str; }

void display() //display the String

{ cout << str; }

void upit(); //uppercase the String

};

//--------------------------------------------------------------

void String::upit() //uppercase each character

{

char* ptrch = str; //pointer to this string

while(*ptrch) //until null,

{

*ptrch = toupper(*ptrch); //uppercase each character

ptrch++; //move to next character

}

}

////////////////////////////////////////////////////////////////

int main()

{

String s1 = "He who laughs last laughs best.";

 

cout << "\ns1="; //display string

s1.display();

s1.upit(); //uppercase string

cout << "\ns1="; //display string

s1.display();

cout << endl;

return 0;

}

3. Используйте массив указателей на строки, представляющие собой названия дней недели, из примера ниже. Напишите функции для сортировки этих строк в алфавитном порядке, используя в качестве основы функции bsort() и order() из программы сортировки, представленной ниже. Сортировать необходимо указатели на строки, а не сами строки.

// lab9_3.cpp

// sort an array of pointers to strings

#include <iostream>

#include <cstring> //for strcmp(), etc.

using namespace std;

const int DAYS = 7; //number of pointers in array

 

int main()

{

void bsort(char**, int); //prototype

//array of pointers to char

char* arrptrs[DAYS] = { "Sunday", "Monday", "Tuesday",

"Wednesday", "Thursday",

"Friday", "Saturday" };

 

cout << "\nUnsorted:\n";

for(int j=0; j<DAYS; j++) //display unsorted strings

cout << *(arrptrs+j) << endl;

 

bsort(arrptrs, DAYS); //sort the strings

 

cout << "\nSorted:\n";

for(j=0; j<DAYS; j++) //display sorted strings

cout << *(arrptrs+j) << endl;

return 0;

}

//--------------------------------------------------------------

void bsort(char** pp, int n) //sort pointers to strings

{

void order(char**, char**); //prototype

int j, k; //indexes to array

 

for(j=0; j<n-1; j++) //outer loop

for(k=j+1; k<n; k++) //inner loop starts at outer

order(pp+j, pp+k); //order the pointer contents

}

//--------------------------------------------------------------

void order(char** pp1, char** pp2) //orders two pointers

{ //if string in 1st is

if(strcmp(*pp1, *pp2) > 0) //larger than in 2nd,

{

char* tempptr = *pp1; //swap the pointers

*pp1 = *pp2;

*pp2 = tempptr;

}

}

4. Добавьте деструктор в программу связного списка. Он должен удалять все элементы списка при удалении объекта класса linklist. Элементы должны удаляться по очереди, в соответствии с их расположением в списке. Протестируйте деструктор путем вывода сообщения об удалении каждого из элементов списка; удалено должно быть также количество элементов, какое было положено в список (деструктор вызывается автоматически для каждого существующего объекта).

// lab9_4.cpp

// linked list includes destructor

#include <iostream>

using namespace std;

////////////////////////////////////////////////////////////////

struct link //one element of list

{

int data; //data item

link* next; //pointer to next link

};

////////////////////////////////////////////////////////////////

class linklist //a list of links

{

private:

link* first; //pointer to first link

public:

linklist() //no-argument constructor

{ first = NULL; } //no first link

~linklist(); //destructor

void additem(int d); //add data item (one link)

void display(); //display all links

};

//--------------------------------------------------------------

void linklist::additem(int d) //add data item

{

link* newlink = new link; //make a new link

newlink->data = d; //give it data

newlink->next = first; //it points to next link

first = newlink; //now first points to this

}

//--------------------------------------------------------------

void linklist::display() //display all links

{

link* current = first; //set ptr to first link

while(current!= NULL) //quit on last link

{

cout << endl << current->data; //print data

current = current->next; //move to next link

}

}

//--------------------------------------------------------------

linklist::~linklist() //destructor

{

link* current = first; //set ptr to first link

while(current!= NULL) //quit on last link

{

link* temp = current; //save ptr to this link

current = current->next; //get ptr to next link

delete temp; //delete this link

}

}

////////////////////////////////////////////////////////////////

int main()

{

linklist li; //make linked list

 

li.additem(25); //add four items to list

li.additem(36);

li.additem(49);

li.additem(64);

 

li.display(); //display entire list

cout << endl;

return 0;

}

5. Предположим, что в функции main() определены три локальных массива одинакового размера и типа (скажем, float). Первые два уже инициализированы значениями. Напишите функцию addarrays(), которая принимает в качестве аргументов адреса грех массивов, складывает соответствующие элементы двух массивов и помещает результат в третий массив. Четвертым аргументом этой функции может быть размерность массивов. На всем протяжении программы используйте указатели.

6. Создайте свою версию библиотечной функции strcmp(s1, s2), которая сравнивает две строки и возвращает -1, если s1 идет первой по алфавиту, О, если в s1 и s2 одинаковые значения, и 1, если s2 идет первой по алфавиту. Назовите вашу функцию compstr(). Она должна принимать в качестве аргументов два указателя на строки char *, сравнивать эти строки посимвольно и возвращать число int. Напишите функцию main() для проверки работы вашей функции с разными строками. Используйте указатели во всех возможных ситуациях.

7. Модифицируйте класс person из программы, представленной ниже, чтобы он включал в себя не только имя человека, но и сведения о его зарплате в виде поля salary типа float. Вам будет необходимо изменить методы setName() и printName() на setData() и printData(), включив в них возможность ввода и вывода значения salary, как это можно сделать с именем. Вам также понадобится метод getSalary(). Используя указатели, напишите функцию salsortQ, которая сортирует указатели массива persPtr по значениям зарплаты. Попробуйте вместить всю сортировку в функцию salsort(), не вызывая других функций, как это сделано в программе PERS0RT. При этом не забывайте, что операция -> имеет больший приоритет, чем операция *, и вам нужно будет написать

if ((*(pp+j))->getSalary() > (*(pp+k))->getSalary())

{ /* меняем указатели местами */

// persort.cpp

// sorts person objects using array of pointers

#include <iostream>

#include <string> //for string class

using namespace std;

////////////////////////////////////////////////////////////////

class person //class of persons

{

protected:

string name; //person's name

public:

void setName() //set the name

{ cout << "Enter name: "; cin >> name; }

void printName() //display the name

{ cout << endl << name; }

string getName() //return the name

{ return name; }

};

////////////////////////////////////////////////////////////////

int main()

{

void bsort(person**, int); //prototype

person* persPtr[100]; //array of pointers to persons

int n = 0; //number of persons in array

char choice; //input char

 

do { //put persons in array

persPtr[n] = new person; //make new object

persPtr[n]->setName(); //set person's name

n++; //count new person

cout << "Enter another (y/n)? "; //enter another

cin >> choice; // person?

}

while(choice=='y'); //quit on 'n'

 

cout << "\nUnsorted list:";

for(int j=0; j<n; j++) //print unsorted list

{ persPtr[j]->printName(); }

 

bsort(persPtr, n); //sort pointers

 

cout << "\nSorted list:";

for(j=0; j<n; j++) //print sorted list

{ persPtr[j]->printName(); }

cout << endl;

return 0;

} //end main()

//--------------------------------------------------------------

void bsort(person** pp, int n) //sort pointers to persons

{

void order(person**, person**); //prototype

int j, k; //indexes to array

 

for(j=0; j<n-1; j++) //outer loop

for(k=j+1; k<n; k++) //inner loop starts at outer

order(pp+j, pp+k); //order the pointer contents

}

//--------------------------------------------------------------

void order(person** pp1, person** pp2) //orders two pointers

{ //if 1st larger than 2nd,

if((*pp1)->getName() > (*pp2)->getName())

{

person* tempptr = *pp1; //swap the pointers

*pp1 = *pp2;

*pp2 = tempptr;

}

}

8. Исправьте функцию additem() из программы связного списка так, чтобы она добавляла новый элемент в конец списка, а не в начало. Это будет означать, что первый вставленный элемент будет выведен первым и результат работы программы будет следующим:

 

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

// linklist.cpp

// linked list

#include <iostream>

using namespace std;

////////////////////////////////////////////////////////////////

struct link //one element of list

{

int data; //data item

link* next; //pointer to next link

};

////////////////////////////////////////////////////////////////

class linklist //a list of links

{

private:

link* first; //pointer to first link

public:

linklist() //no-argument constructor

{ first = NULL; } //no first link

void additem(int d); //add data item (one link)

void display(); //display all links

};

//--------------------------------------------------------------

void linklist::additem(int d) //add data item

{

link* newlink = new link; //make a new link

newlink->data = d; //give it data

newlink->next = first; //it points to next link

first = newlink; //now first points to this

}

//--------------------------------------------------------------

void linklist::display() //display all links

{

link* current = first; //set ptr to first link

while(current!= NULL) //quit on last link

{

cout << current->data << endl; //print data

current = current->next; //move to next link

}

}

////////////////////////////////////////////////////////////////

int main()

{

linklist li; //make linked list

 

li.additem(25); //add four items to list

li.additem(36);

li.additem(49);

li.additem(64);

 

li.display(); //display entire list

return 0;

}

9. Допустим, что нам нужно сохранить 100 целых чисел так, чтобы иметь к ним легкий доступ. Допустим, что при этом у нас есть проблема: память нашего компьютера так фрагментирована, что может хранить массив, наибольшее количество элементов в котором равно десяти (такие проблемы действительно появляются, хотя обычно это происходит с объектами, занимающими большое количество памяти). Вы можете решить эту проблему, определив 10 разных массивов по 10 элементов в каждом и массив из 10 указателей на эти массивы. Массивы будут иметь имена а0, a1, а2 и т. д. Адрес каждого массива будет сохранен в массиве указателей типа int*, который называется ар. Вы сможете получить доступ к отдельному целому используя выражение ap[j] [к], где j является номером элемента массива указателей, а к — номером элемента в массиве, на который этот указатель указывает. Это похоже на двумерный массив, но в действительности является группой одномерных массивов.

Заполните группу массивов тестовыми данными (скажем, номерами 0, 10, 20 и т. д.), а затем выведите их, чтобы убедиться, что все работает правильно.

 

10. Описанный в упражнении 9 подход нерационален, так как каждый из 10 массивов объявляется отдельно, с использованием отдельного имени, и каждый адрес получают отдельно. Вы можете упростить программу, используя операцию new, которая позволит вам выделить память для массивов в цикле и одновременно связать с ними указатели:

for (j = 0: j < NUMARRAYS; j++) // создаем NUMARRAYS массивов

*(ар + j) = new int [ MAXSIZE ]: //no MAXSIZE целых чисел в каждом

Перепишите программу упражнения 9, используя этот подход. Доступ к отдельному элементу массивов вы сможете получить, используя то же выражение, что и в упражнении 9, или аналогичное выражение с указателями: *(*(ap+j)+k).

11. Создайте класс, который позволит вам использовать 10 отдельных массивов из упражнения 10 как один одномерный массив, допуская применение операций массива. То есть мы можем получить доступ к элементам массива, записав в функции main() выражение типа a[j], а методы класса могут получить доступ к полям класса, используя двухшаговый подход. Перегрузим операцию [ ], чтобы получить нужный нам результат. Заполним массив данными и выведем их. Хотя для интерфейса класса использованы операции индексации массива, вам следует использовать указатели внутри методов класса.

12. Указатели сложны, поэтому давайте посмотрим, сможем ли мы сделать работу с ними более понятной (или, возможно, более непонятной), используя их симуляцию в классе.

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

Мы будем использовать один массив типа char для хранения всех типов переменных. Именно так устроена память компьютера: массив байтов (тип char имеет тот же размер), каждый из которых имеет адрес (или, в терминах массива, индекс). Однако C++ не позволит нам хранить данные типа float или int в массиве типа char обычным путем (мы можем использовать объединения, но это другая история). Поэтому мы создадим симулятор памяти, используя отдельный массив для каждого типа данных, которые мы хотим сохранить. В этом упражнении мы ограничимся одним типом float, и нам понадобится массив для него. Назовем этот массив fmemory. Однако значения указателей (адреса) тоже хранятся в памяти, и нам понадобится еще один массив для их хранения. Так как в качестве модели адресов мы используем индексы массива, то нам потребуется массив типа int, назовем его pmemory, для хранения этих индексов.

Индекс массива fmemory (назовем его fmem_top) показывает на следующее по очереди доступное место, где можно сохранить значение типа float. У нас есть еще похожий индекс массива pmemory (назовем его pmem_ top). Не волнуйтесь о том, что наша «память» может закончиться. Мы предполагаем, что эти массивы достаточно большие, чтобы хранить все, что мы захотим, и нам не надо заботиться об управлении памятью.

Создадим класс Float, который мы будем использовать для моделирования чисел типа float, которые будет храниться в fmemory вместо настоящей памяти. Класс Float содержит поле, значением которого является индекс массива fmemory, хранящего значения типа float. Назовем это поле addr. В классе также должны быть два метода. Первый — это конструктор, имеющий один аргумент типа float для инициализации значения. Конструктор помещает значение аргумента в элемент массива fmemory, на который указывает указатель fmem_top, а затем записывает значение fmem_top в массив addr. Это похоже на то, как компоновщик и компилятор хранят обычные переменные в памяти. Второй метод является перегружаемой операцией &. Он просто возвращает значение указателя (индекса типа int) в addr.

Создадим второй класс ptrFloat. Объект этого класса содержит адрес (индекс) в pmemory. Метод класса инициализирует этот «указатель» значением типа int. Второй метод перегружает операцию * (операция разыменования). Его действия более сложны. Он получает адрес из массива pmemory, в котором хранятся адреса. Затем полученный адрес используется как индекс массива fmemory для получения значения типа float, которое располагалось по нужному нам адресу, floats ptrFloat: operator ()

{

return fmemory [ pmemory [ addr ] ];

}

Таким образом мы моделируем действия операции разыменования (*). Заметим, что вам нужно возвращаться из этой функции по ссылке, чтобы можно было использовать операцию * слева от знака равно.

Классы Float и ptrFloat похожи, но класс Float хранит данные типа float в массиве, представляющем собой память, а класс ptrFloat хранит поля типа int (являющиеся у нас указателями, но на самом деле индексами массива) в другом массиве, который тоже представляет собой память.

Это типичное использование этих классов в функции main():

 

Float varl - 1.234: // определяем и инициализируем

Float var2 = 5.678; // две вещественные переменные

ptrFloat ptrl = &varl: // определяем и инициализируем

ptrFloat ptr2 = &var2; // два указателя

cout «” *ptrl = " «*ptrl: // получаем значения переменных

cout «" *ptr2 = “ «*ptr2: // и выводим на экран

*ptrl - 7.123: // присваиваем новые значения

*ptr2 = 8.456: // переменным, адресованным через указатели

cout «" *ptrl = " «*ptrl: // снова получаем значения

cout «" *ptr2 = " «*ptr2: // и выводим на экран

 

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

*ptr1 -1.234 *ptr2 = 5.678

 

<== предыдущая лекция | следующая лекция ==>
 | Предмет дослідження “Теорії та історії соціального виховання”.


Не нашли, что искали? Воспользуйтесь поиском:

vikidalka.ru - 2015-2024 год. Все права принадлежат их авторам! Нарушение авторских прав | Нарушение персональных данных