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

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

Ссылка (reference) является альтернативным именем объекта.

Объявление ссылок:Для каждого типа T есть такой тип T&, называющийся «ссылка на T».

int i = 1;

int& r = i; //r ссылаетсяна i(целое)

r = 25; //i = 25

i = 50; //r = 50

floatf = 3.14;

float& r2 = f; //r2 ссылаетсяна f (вещественное)

r2 = sin(1.25); //тоже, что и f = sin(1.25)

Время жизни ссылок:
• Время жизни ссылок равно или меньше времени жизни объекта, на который они ссылаются
• При уничтожении объекта ссылка на него становится недействительной.

Различия ссылок и указателей: в отличие от указателей, ссылкам не требуется дополнительной памяти; доступ к объекту производится напрямую (разыменовывания не требуется):

int main(...)

{

int i = 1;

int& r = i; // r и i ссылаются на одно и то же целое

int* x = &i; // x указывает на ячейку с r и i

r = 2; // i = 2;

*x = 5; // i = 5;

}

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

int i = 1, k = 2;

int& r = i; // r и i ссылаются на одно и то же целое

int* x = &r; // x указывает на ячейку с r и i

r = 2; // i = 2

*x = 5; // i = 5

x = &k; // x указывает на ячейку с k

*x = 7; // k = 7

// ...

r = k; // i = 7 (присваивает значение k переменной i)

Область применения – изменяемые параметры функций:

void addOneVal(int x)

{

x = x + 1; //увеличить значение x на 1

}

void addOneRef(int& x)

{

x = x + 1; //увеличить значение x на 1

}

int _tmain(int argc, _TCHAR* argv[])

{

int i = 1;

addOneVal(i); //i = 1 - значение i не изменилось

addOneRef(i); //i = 2(!) – значение i изменилось!

return 0;
}

2. Псевдокод. Определение, примеры хорошего и плохого псевдокода.

Псевдокодом называют неформальную нотацию на естественном языке, описывающую работу алгоритма, метода (функции) или программы.

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

Пример плохого псевдокода:

Выделить структуру Student посредством
malloc()
Если malloc() вернет NULL, то
вернуть 0
Увеличить номер студента на 1
Вызвать FillStudent() для заполнения полей
Вернуть указатель на выделенный экземпляр

Пример хорошего псевдокода:

1. Выделить структуру для студента.

2. Если структура может быть выделена:

3. Учесть, что имеется еще один студент;

4. Заполнить поля структуры стандартными значениями;

5. Хранить данные студенте в вызывающей программе.

6. Конец «если».

7. Вернуть true, если студент был создан; иначе вернуть false.

Бинарные файлы. Преимущества и недостатки использования бинарных файлов, функции для записи и чтения бинарных файлов в языке C.

Бинарный (двоичный) файл:
• Последовательность произвольных байтов.
• Название связано с тем, что байты состоят из бит, т.е. двоичных (binary) цифр.

Текстовые файлы хранят только байты, соответствующие печатным символам таблицы ASCII, в то время как бинарные файлы могут хранить байты с любыми значениями [0...255]. Тестовые файлы можно редактировать в любом текстовом редакторе. Бинарные файлы необходимо редактировать в специальных Hex‐редакторах.

Преимущества:

• Выше скорость загрузки и сохранения данных в бинарном файле.
• Обычно требуется меньший объем дискового пространства для хранения данных.
• Проще реализация для программистов.

Недостатки:

• Проблемы с переносимостью на другую платформу.
• «Закрытость» данных: затруднено редактирование вне приложения.
• Негибкость: при смене порядка следования блоков файл становится нечитаемым.

Запись в бинарный файл: Чтение из бинарного файла:
int fwrite( void *buffer, / *откуда* / int size, /*размер*/ int count, /*кол‐во*/ FILE *stream/*куда*/ ); int fread( void *buffer, /*куда*/ int size, /*размер*/ int count, /*кол‐во*/ FILE *stream/*откуда*/ );

Примерсохраненияцелогочиславбинарныйфайл:

#include<stdio.h>

// ...

FILE* fp = fopen("myFile.dat", "w");

int k = 25;

fwrite(&k, sizeof(int), 1, fp);

Пример чтения числа из бинарного файла:

#include<stdio.h>

// ...

FILE* fp = fopen("myFile.dat", "r");

int k = 0;

fread(&k, sizeof(int), 1, fp);

Бинарные файлы. Запись массивов и структур в бинарные файлы. Примеры.

Примерсохранениямассива структурвбинарныйфайл:

#include"stdafx.h"

#include<stdio.h>

// ...

structtovar

{

// ...

};

int _tmain(int argc, _TCHAR* argv[])

{

FILE* fp = fopen("myFile.dat", "wb");

int a = 25; // Количество элементов в массиве структур

tovar *Tov = newtovar[a];

fwrite(&a, sizeof(int), 1, fp);

for (int i = 0; i<a; i++)

fwrite(&Tov[i], sizeof(tovar), 1, fp);

return 0;

}

Пример чтения массива структур из бинарного файла:

#include"stdafx.h"

#include<stdio.h>

// ...

structtovar

{

// ...

};

int _tmain(int argc, _TCHAR* argv[])

{

FILE* fp = fopen("myFile.dat", "rb");

int a = 0; // Количество элементов в массиве структур

fread(&a, sizeof(int), 1, fp);

tovar *Tov = newtovar[a];

for (int i = 0; i<a; i++)

fread(&Tov[i], sizeof(tovar), 1, fp);

return 0;

}

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

Добавление элемента в конец списка:

struct books

{

//…
books* next;

};
books* end(books* book) //Поискконцасписка

{

while (book->next != NULL) //покаестьэлементы

book = book->next; //переходим к следующему элементу

return book;

}
int _tmain(int argc, _TCHAR* argv[])

{
books* start = NULL;//Указатель на первый элемент

books* current = NULL;//Указатель на текущий элемент

if (start == NULL)

{

current = new books;

start = current;

current->next = NULL;

}

else

{

current = end(start);

current->next = new books;

current = current->next;

current->next = NULL;

}
//…
return 0;

}

Добавление элемента в начало списка:

//…
books* tmp = NULL; //Указатель на временный элемент

if (start == NULL)

{//… }

else

{

tmp = new books;

tmp->next = start;

start = tmp;

}
//…
return 0;

}

Добавлениеэлементавпроизвольнуюпозициюсписка:

books* add_rand(books* leftbook, books* newbook) // leftbook - Послекотороговставляем

{ // newbook - Новыйэлемент

if (leftbook != NULL)

{

newbook->next = leftbook->next;

leftbook->next = newbook;

}

returnnewbook;

}

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

Время выполнения операции вставки элемента в произвольную позицию массива и время удаления элемента из произвольной позиции линейно зависит от количества элементов массива. O(n).

Время выполнения операции вставки элемента в произвольную позицию списка и время удаления элемента из произвольной позиции постоянно (т.е. не зависит от количества элементов списка). O(1)

Связныесписки. Удаление элемента из списка. Сравнение с удалением из массива. Примеры.

books* poisk(books* start, intid) // функция поиска элемента списка по номеру

{

while (start != NULL)

{

if (start->nomer == id)

return start;

start = start->next;

}

return NULL;

}

//...

current = poisk(start, id);

tmp = current;

if (tmp == start) //еслипервый

start = current->next;

elseif (tmp->next == NULL) //еслипоследний

{

current = start;

while (current->next->nomer != id)

current = current->next;

current->next = NULL;

}

else //не первый и не последний

{

current = start;

while (current->next->nomer != id)

current = current->next;

current->next = tmp->next;

}

deletetmp;

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

Время выполнения операции вставки элемента в произвольную позицию массива и время удаления элемента из произвольной позиции линейно зависит от количества элементов массива. O(n).

Время выполнения операции вставки элемента в произвольную позицию списка и время удаления элемента из произвольной позиции постоянно (т.е. не зависит от количества элементов списка). O(1)

Связные списки. Обход списка. Сортировка списка. Примеры.

Обход с первого элемента:

books* end(books* start)

{

while (start->next != NULL) //пока есть элементы

start = start->next; //переходим к следующему элементу

returnstart;

}

Сортировка:

structbooks

{

intnomer;

string name;

string author;

int page;

int cost;

books* next;

};

//...

do

{

sortOK = false;

current = start;

while (current->next != NULL)

{

if (current->name > current->next->name)

{

swap(current->name, current->next->name);

swap(current->author, current->next->author);

swap(current->page, current->next->page);

swap(current->cost, current->next->cost);

sortOK = true;

}

current = current->next;

}

} while (sortOK);

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

Ссылка (reference) является альтернативным именем объекта.

Объявление ссылок:Для каждого типа T есть такой тип T&, называющийся «ссылка на T».

int i = 1;

int& r = i; //r ссылаетсяна i(целое)

r = 25; //i = 25

i = 50; //r = 50

floatf = 3.14;

float& r2 = f; //r2 ссылаетсяна f (вещественное)

r2 = sin(1.25); //тоже, что и f = sin(1.25)

Время жизни ссылок:
• Время жизни ссылок равно или меньше времени жизни объекта, на который они ссылаются
• При уничтожении объекта ссылка на него становится недействительной.

Различия ссылок и указателей: в отличие от указателей, ссылкам не требуется дополнительной памяти; доступ к объекту производится напрямую (разыменовывания не требуется):

int main(...)

{

int i = 1;

int& r = i; // r и i ссылаются на одно и то же целое

int* x = &i; // x указывает на ячейку с r и i

r = 2; // i = 2;

*x = 5; // i = 5;

}

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

int i = 1, k = 2;

int& r = i; // r и i ссылаются на одно и то же целое

int* x = &r; // x указывает на ячейку с r и i

r = 2; // i = 2

*x = 5; // i = 5

x = &k; // x указывает на ячейку с k

*x = 7; // k = 7

// ...

r = k; // i = 7 (присваивает значение k переменной i)

Область применения – изменяемые параметры функций:

void addOneVal(int x)

{

x = x + 1; //увеличить значение x на 1

}

void addOneRef(int& x)

{

x = x + 1; //увеличить значение x на 1

}

int _tmain(int argc, _TCHAR* argv[])

{

int i = 1;

addOneVal(i); //i = 1 - значение i не изменилось

addOneRef(i); //i = 2(!) – значение i изменилось!

return 0;
}

2. Псевдокод. Определение, примеры хорошего и плохого псевдокода.

Псевдокодом называют неформальную нотацию на естественном языке, описывающую работу алгоритма, метода (функции) или программы.

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

Пример плохого псевдокода:

Выделить структуру Student посредством
malloc()
Если malloc() вернет NULL, то
вернуть 0
Увеличить номер студента на 1
Вызвать FillStudent() для заполнения полей
Вернуть указатель на выделенный экземпляр

Пример хорошего псевдокода:

1. Выделить структуру для студента.

2. Если структура может быть выделена:

3. Учесть, что имеется еще один студент;

4. Заполнить поля структуры стандартными значениями;

5. Хранить данные студенте в вызывающей программе.

6. Конец «если».

7. Вернуть true, если студент был создан; иначе вернуть false.


Наши рекомендации