Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
л_13_Строки.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
572.42 Кб
Скачать

Динамические строки

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

Для размещения строки в динамической памяти описываем указатель на char и выделяем память с помощью new или malloc.

char *p = new char [m];

char *q = (char *) malloc(m*sizeof(char));

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

Копирование строки в динамическую строку

При копировании строки в динамическую строку необходимо правильно выделять для неё память:

#include <string.h>

int main()

{

char* str = "aaaa bbbbb ccc ddd eeeeeee fffffff";

size_t len = strlen(str); //получение длины строки

char* ptr= new char[len+1]; //выделение места под динамическую строку + '\0'

strcpy_s(ptr, len+1, str); //копирование строки размера len+1 из str в ptr

cout << "ptr=" << ptr << endl; //вывод строки на экран

delete[] ptr; //освобождение памяти

_getch();

return 0;

}

Передача строки в функцию в качестве параметра

Возможность выполнения в функции тех или иных действий со строкой зависит от описания аргумента, передаваемого в функцию (строка-указатель или строка-массив), и от спецификации формального параметра. Анализируйте описания строк в вызывающей функции и строк – формальных параметров и выбирайте последнее, в зависимости от действий, которые необходимо выполнить со строкой в функции.

Рассмотрим сочетания разных описаний строк, которые могут выступать в качестве фактических и формальных параметров.

Пример_1: в main()– строка-массив; в функции – строка-указатель

//пример_1_1: строка передается как неконстантный указатель на неконстантные данные

void convertToUppercase (char *);

int main()

{

char string [ ] = "aaaaaaa"; //string - константный указатель на неконстантные данные

cout << string <<endl; //string++ - ошибка!!!, string[i]=i; - ок!!!

convertToUppercase(string);

cout << string <<endl;

_getch();

return 0;

}

void convertToUppercase (char *sPtr)

{

while (*sPtr != '\0') { // sPtr - неконстантный указатель на неконстантные данные

*sPtr = toupper(*sPtr);

++sPtr;

}

}

//пример_1_2: строка передается как неконстантный указатель на константные данные

void convertToUppercase (const char *);

int main()

{

char string [ ] = "aaaaaaa"; //string - константный указатель на неконстантные данные

cout << string <<endl;

convertToUppercase (string);

cout << string <<endl;

_getch();

return 0;

}

void convertToUppercase (const char *sPtr)

// sPtr – неконстантный указатель на константные данные

//т.е. данные «только для чтения»

{

for ( ; *sPtr != '\0'; sPtr++) //модифицировать неконстантный указатель можно

{cout << *sPtr; //читать константное значение можно

// *sPtr = toupper(*sPtr); - в данном случае ошибка!!!

} //нельзя модифицировать константные данные

}

//пример_1_3: строка передается как константный указатель на неконстантные данные

void convertToUppercase (char *const);

int main()

{

char string [ ] = "aaaaaaa"; //string – константный указатель на неконстнатные данные

cout << string <<endl;

convertToUppercase(string);

cout << string <<endl;

_getch();

return 0;

}

void convertToUppercase (char *const sPtr)

{ while (*sPtr != '\0') { // sPtr – константный указатель на неконстантные данные

*sPtr = toupper(*sPtr); //неконстантные данные модифицировать можно

// ++sPtr; ошибка!!! константный указатель модифицировать нельзя

}

}

Константный указатель на неконстантные данные – это указатель, который всегда указывает на одну и ту же ячейку памяти, данные в которой можно модифицировать посредством указателя. Этот вариант реализуется по умолчанию для имени массива. Имя массива – это константный указатель на начало массива. Используя имя массива и индексы массива можно обращаться ко всем данным в массиве и изменять их.

Указатели, объявленные как const, должны получить начальные значения при своем объявлении (если указатель является параметром функции, он получает начальное значение, равное указателю, который передается в функцию). Обратите внимание, что при объявлении константного указателя, ключевое слово const пишется между символом ‘*’ и идентификатором указателя, например: int *const ptr . Постоянство передаваемого значения задает const слева от *, например: const int * ptr.

//пример_1_4: строка передается как константный указатель на константные данные

#include <ctype.h>

void convertToUppercase (const char *const, int);

int main()

{

const int n=8;

char string [n] = "aaaaaaa"; //string – константный указатель на неконстантные данные

cout << string <<endl;

convertToUppercase(string, n);

cout << string <<endl;

_getch();

return 0;

}

void convertToUppercase (const char *const sPtr, int n)

{

for ( int i=0; i<n; i++) // sPtr – константный указатель на константные данные

{//*sPtr = toupper(*sPtr); //нельзя модифицировать константные данные

cout << sPtr[i] << endl;

//sPtr++; //ошибка !!!нельзя модифицировать константный указатель

}

}

Константный указатель на константные данные имеет наименьший уровень привилегий. Такой указатель всегда указывает на одну и ту же ячейку памяти и данные в этой ячейке нельзя модифицировать. Это выглядит так, как если бы массив нужно было передать функции, которая его только просматривает, «читает», но не модифицирует.