Как вернуть структуру из функции c
Подскажите пожалуйста новичку, как на СИ возвратить структуру из функции
struct myStruct < UINT16 Param1; UINT16 Param2; >;
VOID. myFunc() < struct myStruct *myStruct; myStruct->Param1 = 10; myStruct->Param2 = 20; // Как сдесь написать return что бы вернуть структуру myStruct . Подскажите новичку пожалуйста return . ; >;
По форуму искал но так и ничего толком не понял, можно ожалуйста наглядный пример, большое спасибо
Re: Возврат структуры из функции на СИ
От: | gandjustas | http://blog.gandjustas.ru/ |
Дата: | 11.08.07 12:45 | |
Оценка: |
Мжет лучше еще раз перечитать книжку по С ?
Столько ошибок в одной тривиальной функции я еще не видел.
Re: Возврат структуры из функции на СИ
От: | Аноним | |
Дата: | 11.08.07 12:49 | |
Оценка: | 3 (1) |
Здравствуйте, AlexBosen, Вы писали:
AB>Подскажите пожалуйста новичку, как на СИ возвратить структуру из функции
AB>Имеем структуру:
AB>
AB>struct myStruct AB> < AB>UINT16 Param1; AB> UINT16 Param2; AB>>; AB>
AB>Имеем функцию:
AB>
AB>VOID. myFunc() AB> < AB>struct myStruct *myStruct; AB> myStruct->Param1 = 10; AB> myStruct->Param2 = 20; AB> // Как сдесь написать return что бы вернуть структуру myStruct . Подскажите новичку пожалуйста AB> return . ; AB>>; AB>
AB>По форуму искал но так и ничего толком не понял, можно ожалуйста наглядный пример, большое спасибо
void* myFunc() < struct myStruct *myStruct; myStruct->Param1 = 10; myStruct->Param2 = 20; return ( (void*)(myStruct) ); >;
но это не совсем красиво
ИМХО лучше так:
// . myStruct *pStruct = new myStruct; myFunc( *pStruct ); // . void myFunc(myStruct& aStruct) < aStruct.Param1 = 10; aStruct.Param2 = 20; >;
Re[2]: Возврат структуры из функции на СИ
От: | AlexBosen |
Дата: | 11.08.07 12:52 |
Оценка: |
Здравствуйте, gandjustas, Вы писали:
G>Мжет лучше еще раз перечитать книжку по С ?
G>Столько ошибок в одной тривиальной функции я еще не видел.
Спасибо за совет, но я же новичек и только учусь
Re: Возврат структуры из функции на СИ
От: | Аноним | |
Дата: | 11.08.07 12:52 | |
Оценка: | 6 (2) |
Здравствуйте, AlexBosen, Вы писали:
AB>Подскажите пожалуйста новичку, как на СИ возвратить структуру из функции
AB>Имеем структуру:
AB>
AB>struct myStruct AB> < AB>UINT16 Param1; AB> UINT16 Param2; AB>>; AB>
AB>Имеем функцию:
AB>
AB>VOID. myFunc() AB> < AB>struct myStruct *myStruct; AB> myStruct->Param1 = 10; AB> myStruct->Param2 = 20;
Так нельзя. Для структуры надо выделить память
1. статически
struct myStruct s;
2. либо динамически
struct myStruct* ps = (myStruct*)malloc(sizeof(myStruct));
Во втором случае не забудь освободить память (free(. )).
AB> // Как сдесь написать return что бы вернуть структуру myStruct . Подскажите новичку пожалуйста AB> return . ; AB>>; AB>
struct myStruct myFunc()
struct myStruct* myFunc()
AB>По форуму искал но так и ничего толком не понял, можно ожалуйста наглядный пример, большое спасибо
Re[2]: Возврат структуры из функции на СИ
От: | Awaken | |
Дата: | 11.08.07 12:56 | |
Оценка: | 2 (1) |
А>myStruct *pStruct = new myStruct;
забыли вы Си совсем
в C нет new/delete. по значению тоже не передашь т.к. нет конструкторов копирования
единственный вариант тут это calloc/malloс . или объявить ее глобальной переменной
Re[3]: Возврат структуры из функции на СИ
От: | Аноним | |
Дата: | 11.08.07 13:06 | |
Оценка: | 3 (2) |
Здравствуйте, Awaken, Вы писали:
А>>myStruct *pStruct = new myStruct;
A>забыли вы Си совсем
A>в C нет new/delete. по значению тоже не передашь т.к. нет конструкторов копирования
Чего? Comeau в режиме С99 компилит нормально.
Re[3]: Возврат структуры из функции на СИ
От: | Аноним | |
Дата: | 11.08.07 13:10 | |
Оценка: | 3 (1) |
Здравствуйте, Awaken, Вы писали:
А>>myStruct *pStruct = new myStruct;
A>забыли вы Си совсем
A>в C нет new/delete. по значению тоже не передашь т.к. нет конструкторов копирования
A>единственный вариант тут это calloc/malloс . или объявить ее глобальной переменной
Все правильно, это ++ вариант.
плюсы съели остатки моего мозга
Re[4]: Возврат структуры из функции на СИ
От: | Awaken |
Дата: | 11.08.07 14:09 |
Оценка: |
А>Чего? Comeau в режиме С99 компилит нормально.
за С99 не слежу. ты прав, там это стало стандартной фичей.
Re[5]: Возврат структуры из функции на СИ
От: | Аноним |
Дата: | 11.08.07 14:29 |
Оценка: |
Здравствуйте, Awaken, Вы писали:
А>>Чего? Comeau в режиме С99 компилит нормально.
A>за С99 не слежу. ты прав, там это стало стандартной фичей.
А какой Си Вы имели в виду? С89/С90 тоже поддерживает передачу и возврат структур по значению. Разве в K&R C было по другому?
Re[2]: Возврат структуры из функции на СИ
От: | AlexBosen |
Дата: | 11.08.07 14:55 |
Оценка: |
Здравствуйте, Аноним, Вы писали:
struct myStruct s; struct myStruct myFunc()
Огромное спасибо Все получилось!
Возврат значения из функции
Чистая функция, это функция, которая:
- является детерминированной;
- не обладает побочными эффектами.
int f(int x) int y = 0;
int z = 0;
y = 2 * x;
z = y + 1;
return z / 3;
>
Возврат нескольких разнотипных значений
Что делать, если функции нужно вернуть сразу два или три значения, причем, возможно, разных типов?
Увы, просто так этого сделать нельзя.
Такие ситуации можно разделить на два характерных случая:
- Возвращаемые значения фактически представляют собой единый объект.
Пример 1: функции getPixelColor(x, y) передаются координаты точки на текстуре, возвращается ее цвет. - Возвращаемые данные не вполне связаны между собой (являются различными объектами или просто набором слабо связанных данных).
Пример 2: функция getStudentMark() получает с клавиатуры строчку с фамилией студента и его оценку по информатике.
Пример 1
Итак, функции getPixelColor(x, y) передаются координаты точки на текстуре, надо вернуть ее цвет.
Цвет в модели RGB TrueColor описывается тремя целыми беззнаковыми числами в диапазоне от 0 до 255.
Здесь цвет точки однозначно представляет собой объект, который должен быть выделен в структуру данных.
typedef struct unsigned char r, g, b; //компоненты цвета red, green, blue
> tColor;
Как только создана такая Си-структура, вопрос передачи цвета из функции решен:
tColor getPixelColor(int x, int y)
tColor color; //локальная переменная, куда будем доставать цвет.
//. достать цвет с текстуры (без подробностей)
return color;
>
Пример 2
Функция getStudentMark() должна получить с клавиатуры строчку с фамилией студента и его оценку по информатике. При этом для студентов уже существует структура данных:
typedef struct int studentID; //идентификатор студента
char lastName[30]; //фамилия
char name[30]; //имя
unsigned int groupNumber; //номер группы
> tStudent;
Заметим, что эта структура нам для возврата значения не подходит. Мы возвращаем лишь фамилию и оценку.
Фамилия — лишь часть этой структуры данных, остальное нам в этой функции заполнить неоткуда. Заполнить пустыми значениями? А вдруг мы в месте вызова забудем, что в возвращенном экземпляре структуры правдива лишь фамилия?
Оценку по информатике можно было бы внести в эту структуру, но, согласитесь, будет странно, если оценка будет атрибутом самого студента, а не его строчки в журнале. Это не логично, особенно если учесть, что другая функция, работающая со списком студентов, будет вынуждена «выдумывать» теперь уже оценку.
Выход может состоять в том, чтобы создать «одноразовую» структуру данных, осознавая ограниченность ее применения: только для возврата из данной конкретной функции.
typedef struct char lastName[30]; //фамилия
unsigned int mark; //оценка
> tStudentMark;
Будет хорошо, если эта структура выработана логично, и она нам еще понадобится в других функциях, тогда она «перерастет» свою одноразовость.
Функция будет выглядеть так:
tStudentMark getStudentMark()
tStudentMark studentMark; //локальная переменная, куда будем доставать фамилию и оценку.
//. достать фамилию и оценку (без подробностей)
return studentMark;
>
char lastName[20];
int mark;
tStudentMark studentMark; //переменная, которая нужна только для разбора значений из функции
studentMark = getStudentMark();
lastName = studentMark.lastName;
mark = studentMark.mark;
Текста получилось много, зато мы сохранили «чистоту функции».
Передача через нарушение чистоты функции
Есть еще два способа вернуть из функции значение:
- Передавать параметры не по значению, а по адресу, а изнутри функции просто менять их значения.
Пример: функция getStudentMark() получает в качестве параметров адреса строки и оценки, считывает с клавиатуры строчку с фамилией студента и его оценку по информатике, и сохраняет в параметры. - Сохранять возвращаемые значения в глобальных переменных.
Стандартной функции open(filename, O_RDONLY) передается имя файла и флаги доступа, функция возвращает открывает файл, и возвращает его дескриптор (число-идентификатор, необходимое для последующих обращений к открытому файлу), однако может случиться ошибка доступа, причем код ошибки важен.
Пример
Итак, функция getStudentMark() получает в качестве параметров адрес строки и адрес оценки, считывает с клавиатуры строчку с фамилией студента и его оценку по информатике, и сохраняет в параметры.
Попробуем написать функцию с таким заголовком:
void getStudentMark(char lastName[], int *mark)
scanf(«%s%d», lastName, mark);
>
char lastName[20];
int mark;
getStudentMark(lastName, &mark);
Плюсы: отказались от «одноразовой» структуры данных, уменьшили длину кода.
Минусы: корректность памяти определяется местом вызова. Внутри функции хорошо бы проверять корректность данных адресов памяти.
Возврат структуры из функции
Помогите разобраться. В функции мы создаем структуру, область видимости которой ограничивается этой функцией. Из нее мы возвращаем указатель на эту структуру.
Мне думалось, что подобное работать не должно. Т.к. объявленная структура при выходе за области действия функции перестает существовать, и, в таком случае, возвращаемый указатель должен ссылаться на какой-то мусор.
Т.е. получается, область памяти остается без изменений, мы просто не можем обращаться к структуре вне функции по имени? Может ли быть такое, что эта область памяти изменится каким-либо другим образом? Структура хранится в стеке же?
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Функции: возврат структуры
struct my_info < //поля >my_struct; //структура struct my_info funct (struct my_info);.
Возврат структуры функцией через указатель
Здравствуй. После С++ никак не могу понять, как сделать. Нужно создать функцию struct A*.
Возврат структуры из функции
Добрый день! Я только начинаю, и сразу стал путаться с массивами и структурами с горем попалам.
Возврат структуры из функции
Всем доброго времени суток. awesome.h struct point < float x = 1; float y = 1; >; struct.
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
Сообщение было отмечено Garcian как решение
Решение
Всё правильно. Структура может некоторое время и просуществовать, и обращение к ней будет давать правильные результаты, пока та область стека где она находилась, не будет затёрта выполняющейся функцией (при выделении ей новых переменных) или переменными новой вызываемой функции. Тут просто повезло. Единственной вызываемой функцией оказалась printf(), а поля структуры Ms ей передали при вызове, т. е. фактически к структуре обратились, извлекли её поля и присвоили их значения переменным-параметрам функции printf() ещё до самого вызова функции printf(). Дальше в процессе своей работы функция printf() наверняка затёрла структуру Ms со всеми её полями (но сохранение значений полей структуры в стековом кадре данного вызова printf() произошло раньше, непосредственно перед вызовом printf()). Так что в общем-то пример содержит ошибку, хотя в данном случае он и работает правильно.
Тут два выхода. Или объявить структуру Ms глобально, или объявить её внутри функции, но с квалификатором static. В последнем случае структура будет находиться в области глобальных данных в памяти процесса, фактически она будет глобальной переменной, но видимо её имя будет только внутри функции, в которой она объявлена, извне к ней обратиться будет нельзя. В смысле области видимости она будет похожа на локальную переменную. А по поведению она будет в общем-то глобальной переменной.
12243 / 7373 / 1734
Регистрация: 25.07.2009
Сообщений: 13,522
Сообщение от Garcian
Может ли быть такое, что эта область памяти изменится каким-либо другим образом?
Может, и скорее всего так и произойдёт, сделай программа ещё что-нибудь. Правильный путь — внутри функции выделять память под структуру из кучи, заполнять поля и возвращать указатель. Только не забывать потом освобождать память, а то она не резиновая.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mystruct* mystruct_new(const int a, const int b) { mystruct * ms = malloc(sizeof(mystruct)); if ( ! ms ) return NULL; // если памяти не хватило. ms->a = a; ms->b = b; return ms; } // где-то в программе mystruct * ms = mystruct_new(13, 69); if ( ! ms ) { fprintf(stderr, "Memory error!\n"); exit(1); } //do something free(ms);
239 / 265 / 218
Регистрация: 14.11.2016
Сообщений: 1,035
Garcian, выделяй память ( malloc ) под указатель, записывай потом в структуру значения (не забывай разыменовывать только указатель), и после возвращай указатель.
1 2 3 4 5 6 7
myStruct* simplefunc(int a, int b) { myStruct *ptr_item = ( myStruct*) malloc(sizeof(myStruct)); ptr_item->a = a; ptr_item->b = b; return ptr_item; }
Только потом не забывай в main() освободить выделенную память, чтобы не произошло утечки ( free(ptr); ).
Где ptr , это указатель на структуру (в твоём случае это будет ms_p ).
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
Можно и выделить память для новой структуры динамически, из кучи, а можно и объявить структуру как статическую переменную, в этом случае она будет иметь всегда один и тот же статический адрес.
Вот твой пример со статически объявленной структурой.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
#include typedef struct { int a; int b; } myStruct; myStruct* simplefunc(int a, int b) { static myStruct Ms; Ms.a = a; Ms.b = b; return &Ms; } int main(int argc, char** argv) { myStruct *ms_p = simplefunc(3, 5); printf("a: %d b: %d\n", ms_p->a, ms_p->b); return 0; }
Только тут надо помнить две вещи.
1. При каждом новом вызове simplefunc() структура будет перезаписываться новыми параметрами, но это будет всё та же, прежняя переменная, хранящаяся по тому же самому старому адресу. Новой переменной создано не будет. Адрес функция simplefunc() будет возвращать каждый раз один и тот же. То есть новых копий структуры при каждом последующем вызове функция не порождает, она работает при каждом своём вызове с одной и той же копией, и эта единственная копия при каждом новом вызове будет перезаписана. Это может не годиться в некоторых случаях. Если же память для структуры выделяется динамически функцией malloc(), как тебе предложили другие форумчане в своих постах, при каждом вызове функции simplefunc() будет создана новая копия структуры. В некоторых случаях этот вариант является более приемлемым.
2. Этот подход со статической переменной (т. е. с переменной, объявленной с квалификатором static), возможно, не подойдёт для многопоточной программы.
Добавлено через 10 часов 48 минут
Ещё небольшое добавление хотел сделать, Garcian.
Твоя задача очень известная и по-моему во многих пособиях по C она рассматривается (мне она попадалась, а уже где, не помню).
Допустим, нам нужно объявить некоторую переменную в теле функции, вычислить значение этой переменной в функции, а по выходу из функции вернуть указатель на эту переменную. Если переменная локальная и имеет автоматический класс памяти, такое решение будет работать через раз и оно считается грубой ошибкой. Почему, я писал выше (переменная определена в стеке и она будет затёрта со временем другими данными). Чтобы решить эту проблему, объявляем переменную с классом памяти static, она после этого существует всё время жизни программы (а не только пока лишь выполняется функция, в которой она объявлена) и в этом отношении она подобна переменным, объявленным глобально, и на эту переменную можно возвращать указатель при выходе из функции.
P.S.
Хотелось бы хороший пример привести такой функции, чтобы он не выглядел надуманно, но ничего пока в голову не приходит.
Добавлено через 10 минут
P.P.S.
Ну и конечно, такое решение имеет свои ограничения, связанные с тем, что у нас существует всего один экземпляр переменной и каждый раз функция при своём вызове будет перезаписывать значение, хранящееся в этом экземпляре, и возвращать один и тот же указатель на этот единственный экземпляр. Об этом я также писал выше. Просто об этом надо помнить.
Регистрация: 13.11.2012
Сообщений: 173
Всем спасибо за Ваши ответы на вопрос, который не давал мне заснуть!) И тем более не ожидал таких исчерпывающих ответов, очень приятно! JohnyWalker, а если саму функцию пометить как static, это же тоже будет верно?
ПС: я не полный новичок в программировании, просто так сложилось, что жизнь кинула на самые «низы» уровня программирования. Жаль, что начинал я не с этого, т.к. только сейчас складывается полная картина происходящего. Но уж лучше поздно, чем никогда)
200 / 87 / 9
Регистрация: 15.11.2010
Сообщений: 472
Garcian, функцию можно пометить ключевым словом static. Но функции в C (по крайней мере в стандартном C, не в ГНУшном его расширении, допускающем вложение функций друг в друга) — это всегда глобальные, внешние объекты (в отличие от переменных, которые могут быть и глобальными, и локальными). И функции, и глобальные переменные тоже можно помечать словом static, но смысл этого будет совсем другой, в отличие от локальных переменных, объявленных статическими. Они от этого как были, так и останутся глобальными объектами, но область их видимости сократится до пределов того файла, в котором они объявлены. Дело в том (ну ты это знаешь, наверное, Garcian), что в Си принята раздельная пофайловая компиляция. Каждый файл транслиуется отдельно и независимо, и при этом порождается свой объектный модуль. Так вот, все глобальные объекты — функции и переменные (но не типы) — считаются внешними объектами, видимыми в других файлах, если они не помечены словом static. Переменную или функцию, описанную в одном файле, можно объявить в другом файле. Объявление внешней функции в другом файле — это её прототип. Объявление (но не описание!) внешней переменной делается с ключевым словом (фиг его знает, чем оно считается, — квалификатором, модификатором или ещё чем) extern. Компилятор, встречая в тексте файла имена объявленных, но не описанных объектов, порождает какие-то свои адреса и таблицу имён. Дальше эти имена и адреса разрешаются уже линкером при компоновке объектных модулей в окончательный исполняемый файл. Так вот, если в разных исходных файлах программы будет описано несколько глобальных объектов (переменных, либо функций) с одним именем, произойдёт конфликт имён. Причём случится он не на уровне компилятора (т. к. файлы транслируются в C независимо и на стадии компиляции они друг друга не видят), а на уровне линкера. Линкер встретит, допустим, 2 объектных файла, в каждом из которых описана переменная с именем a, и не будет знать, что с ними делать, и выдаст ошибку конфликта имён. А ключевое слово static, применённое к глобальной функции или переменной, позволяет сделать имя переменной или функции невидимым для других объектных модулей. Другие модули не смогут воспользоваться этими объектами. Ими пользоваться можно будет только внутри того же файла, в котором они объявлены. И даже если в программе объявлена в каком-то другом файле ещё одна переменная или функция с тем же именем, но уже без слова static, конфликта имён не произойдёт.
Коротко говоря. Помечание словом static глобальных переменных и функций ограничивает область их видимости тем файлом, в котором они объявлены. Это способ изоляции объектов, который позволяет избежать конфликта имён на уровне линкера. Если сравнивать C с другими языками, в которых есть нормальные полноценные модули, такими как Модула-2, Оберон, Java, C#, то все объекты, не помеченные словом static, являются экспортируемыми объектами модуля, а объекты, помеченные словом static, являются внутренними скрытыми объектами модуля, не подлежащими экспорту.
Как-то так. Наверняка в моих словах есть куча неточностей, этим вопросом владею недостаточно хорошо. Пусть меня другие форумчане поправят, если найдут ошибки в моих словах. Но суть именно такая. Надеюсь, что понятно написал
C++. Структуры. Часть 4. Структуры и функции. Передача структуры в функцию в среде CLR. Возврат структуры из функции
Структуры. Часть 4. Структуры и функции. Передача структуры в функцию в среде CLR . Возврат структуры из функции
Поиск на других ресурсах:
1. Какие существуют способы передачи структуры в функцию?
Существует 2 способа передачи native -структуры в функцию в качестве параметра:
- передача структуры по значению. При такой передаче делается копия структурной переменной в памяти. Если структура имеет большой размер, то такой способ неэффективен. Преимуществом этого способа есть то, что все манипуляции с копией структуры в функции не влияют на исходную переменную;
- передача указателя на структуру. В этом случае передается только указатель на структуру а не вся структура. Если структура занимает большой объем памяти, то такой способ обеспечивает быструю передачу значений структурной переменной в функцию. Это связано с тем, что передается только указатель на структуру. Недостатком этого способа есть то, что в функции случайно можно изменить значения исходной структурной переменной, в тех случаях когда это нежелательно.
2. Какие есть способы возврата структуры из функции?
Так же, как и при передаче структуры в функцию (см. п.1), существуют 2 способа возврата:
- возврат структуры по значению;
- возврат указателя на структуру.
Преимущества и недостатки каждого способа такие же, как описано в п. 1.
3. Пример передачи native -структуры в функцию по значению
Пусть в модуле «MyStruct.h» даны объявления native -структуры:
// native-структура, которая описывает точку на координатной плоскости struct MyPoint < int x; int y; >;
Пусть в некотором классе объявляется функция EqualPoints() , которая сравнивает две точки на координатной плоскости. Функция возвращает true , если точки эквивалентны (равны между собой). В другом случае функция возвращает false .
// функция, которая сравнивает на равенство две точки public: bool EqualPoints(MyPoint p1, MyPoint p2) < bool f = false; if ((p1.x == p2.x) && (p1.y == p2.y)) f = true; return f; >
Тогда использование функции EqualPoints() может быть следующим:
// подключение модуля "MyStruct.h" #include "MyStruct.h" . // передача native-структуры в функцию по значению bool f_equal; MyPoint pt1, pt2; // p1, p2 – переменные типа "структура" // заполнение значениями pt1.x = 23; pt1.y = 35; pt2.x = 23; pt2.y = 35; f_equal = this->EqualPoints(pt1, pt2); // f_equal = true pt1.x = 100; f_equal = EqualPoints(pt1, pt2);
4. Пример передачи native -структуры в функцию по указателю
Пусть задана native -структура:
// native-структура struct MyPoint < int x; int y; >;
Ниже реализована функция, которая сравнивает на равенство значения структурных переменных. Функция получает указатель на структуру.
// передача указателя на структуру MyPoint bool EqualPointsP(MyPoint * p1, MyPoint * p2) < bool f = false; if ((p1->x == p2->x) && (p1->y == p2->y)) f = true; return f; >
Программный код, демонстрирующий использование функции EqualPoints() .
// Передача структуры по указателю MyPoint p1; MyPoint p2; bool f_equal; p1.x = 28; p1.y = 35; p2.x = 28; p2.y = 35; f_equal = EqualPointsP(&p1, &p2); // f_equal = true p2.y = 100; f_equal = EqualPointsP(&p1, &p2); // f_equal = false
5. Как передать в функцию managed -структуру, которая объявлена с квалификатором ref ? Пример
Пусть задана следующая ref -структура.
// ref-структура ref struct MyPointRef < int x; int y; >;
Структуры с квалификатором ref есть структурами ссылочного типа. Для таких структур память должна выделяться с помощью утилиты gcnew . Поэтому, в функцию можно передать только ссылку на такие структуры.
Пусть дана функция LengthRef() , которая определяет длину линии, которая соединяет 2 точки. Функция получает две ref -структуры в качестве параметров.
// Функция, определяющая длину между двумя точками float LengthRef(MyPointRef ^p1, MyPointRef ^p2) < float l; l = Math::Sqrt((p1->x-p2->x)*(p1->x-p2->x) + (p1->y-p2->y)*(p1->y-p2->y)); return l; >
Использование функции LengthRef() в некотором программном коде.
// передача ref-структуры в функцию MyPointRef ^ pt1; MyPointRef ^ pt2; float len; // выделение памяти для ref-структур pt1 = gcnew MyPointRef; pt2 = gcnew MyPointRef; // заполнение ref-структур значениями pt1->x = 35; pt1->y = 35; pt2->x = 40; pt2->y = 40; len = LengthRef(pt1, pt2); // len = 7.071068
6. Как передать в функцию managed -структуру, которая объявлена с квалификатором value ? Пример
Managed -структуру, объявленную с квалификатором value можно передать в функцию одним из двух способов:
- по значению;
- по указателю.
Ниже приведены оба способа для value -структуры MyPointValue , которая имеет следующее объявление.
// value-структура value struct MyPointValue < int x; int y; >;
Способ 1.
Пусть задана функция LengthValue() , определяющая расстояние между двумя точками. Функция получает входным параметром две структуры типа MyPointValue . Структуры передаются как параметр-значение.
// определение расстояния между двумя точками float LengthValue(MyPointValue p1, MyPointValue p2) < float len; len = (float)Math::Sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); return len; >
Пример использования функции LengthValue() в другом программном коде.
// передача value-структуры по значению MyPointValue pt1; MyPointValue pt2; float len; pt1.x = 35; pt1.y = 50; pt2.x = 40; pt2.y = 55; len = LengthValue(pt1, pt2); // len = 7.071068
Способ 2. Передача структуры по указателю.
Пусть задана функция LengthValue() , получающая два указателя на структуры типа MyPointValue .
// функция получает указатель на value-структуру float LengthValueP(MyPointValue *p1, MyPointValue *p2) < float len; len = Math::Sqrt((p1->x-p2->x)*(p1->x-p2->x) + (p1->y-p2->y)*(p1->y-p2->y)); return len; >
Использование функции LengthValue() в программе.
// передача value-структуры по указателю MyPointValue pt1; MyPointValue pt2; float len; pt1.x = 0; pt1.y = 0; pt2.x = 10; pt2.y = 10; len = LengthValueP(&pt1, &pt2); // len = 14.14214
7. Как реализовать возврат экземпляра native -структуры из функции? Пример
Возвратить native -структуру можно:
- по значению;
- по адресу.
Пусть задана структура MyPoint
// native-структура struct MyPoint < int x; int y; >;
Пусть в программе реализована функция GetCenterLine() , которая вычисляет координаты середины отрезка, соединяющего 2 точки. Функция получает 2 параметра – координаты концов отрезка.
// функция, возвращающая native-структуру // функция вычисляет координаты середины отрезка MyPoint GetCenterLine(MyPoint p1, MyPoint p2) < MyPoint res; res.x = (p1.x + p2.x)/2; res.y = (p1.y + p2.y)/2; return res; >
Демонстрация возврата native -структуры по значению.
MyPoint pt1; MyPoint pt2; MyPoint res; // результат, память уже выделена pt1.x = 30; pt1.y = 20; pt2.x = 36; pt2.y = 40; res = GetCenterLine(pt1, pt2); // res - координаты середины отрезка
8. Пример возврата из функции указателя на native -структуру
Пусть задана структура MyPoint
// native-структура struct MyPoint < int x; int y; >;
Пусть реализована функция GetCenterLine() , которая получает 2 точки и возвращает указатель на структуру. В теле функции реализовано выделение памяти для структуры оператором new .
MyPoint * GetCenterLine(MyPoint p1, MyPoint p2) < MyPoint * res; // указатель на структуру MyPoint // выделение памяти для структуры res = new MyPoint; // вычисление середины отрезка - заполнение значениями resP->x = (p1.x + p2.x)/2; resP->y = (p1.y + p2.y)/2; return res; >
Демонстрация работы с функцией GetCenterLine() .
// возвращение native-структуры по указателю MyPoint * resPt; // указатель на структуру – память для структуры еще не выделена MyPoint pt1, pt2; // экземпляры структуры pt1.x = 28; pt1.y = 40; pt2.x = 38; pt2.y = 50; // вызов функции GetCenterLine() // для указателя resPt память выделяется внутри функции resPt = GetCenterLine(pt1, pt2); // проверка int d; d = resPt->x; // d = 33 d = resPt->y; // d = 45
9. Как возвратить экземпляр value -структуры из функции?
Если в среде CLR описана структура с квалификатором value , то возврат экземпляра такой структуры из функции ничем не отличается от возвращения native -структуры (см. п. 7.).
10. Пример возврата указателя ( ^ ) на value -структуру
Если структура объявлена с квалификатором value , то функция может возвращать указатель на эту структуру. Допускается использование двух видов указателей:
- классического указателя, который обозначается символом ‘*’ . Возврат такого указателя из функции не отличается от возврата указателя на native -структуру (см. п. 8);
- указателя, предназначенного для работы с объектами среды CLR . Такой указатель обозначается символом ‘^‘ . Память для такого указателя выделяется утилитой gcnew . Ниже приведен пример возврата из функции такого указателя на value -структуру.
Пусть объявлена структура с квалификатором value
// value-структура value struct MyPointValue < int x; int y; >;
Пусть нужно реализовать функцию GetCenterLineVP() , которая получает 2 точки и возвращает указатель на результирующую value -структуру. Результирующая структура содержит координаты центра отрезка, который соединяет точки. Функция имеет следующий вид:
// функция возвращает указатель на value-структуру MyPointValue ^ GetCenterLineVP(MyPointValue p1, MyPointValue p2) < MyPointValue ^ pv; // указатель на структуру MyPointValue pv = gcnew MyPointValue; pv->x = (p1.x + p2.x)/2; pv->y = (p1.y + p2.y)/2; return pv; >
Демонстрация вызова функции из другого программного кода:
// создание экземпляров структур с инициализацией MyPointValue pt1 = < 20, 30 >; MyPointValue pt2 = < 40, 60 >; // указатель на структуру MyPointValue MyPointValue ^ resPt; // вызов функции GetCenterLineVP() // внутри функции выделяется память для структуры, // на которую указывает resPt resPt = GetCenterLineVP(pt1, pt2); // проверка int d; d = resPt->x; // d = 30 d = resPt->y; // d = 45
11. Пример возврата из функции структуры, которая объявлена с квалификатором ref
Для структуры, которая объявлена с квалификатором ref есть определенные особенности использования. Такая структура есть структурой ссылочного типа. Поэтому функция должна возвращать ссылку на такую структуру (указатель на структуру). Возвратить экземпляр ref -структуры (по значению) из функции не удастся (см. п. 5).
Пусть объявлена структура
// ref-структура ref struct MyPointRef < int x; int y; >;
Тогда функция, которая получает 2 точки в качестве параметров и находит центр между двумя точками будет иметь приблизительно следующий вид:
// функция, возвращающая ref-структуру MyPointRef ^ GetCenterLineRef(MyPointRef ^p1, MyPointRef ^p2) < MyPointRef ^resPt; // выделение памяти для указателя resPt resPt = gcnew MyPointRef; // заполнение значениями полей указателя resPt->x = (p1->x + p2->x)/2; resPt->y = (p1->y + p2->y)/2; return resPt; >
Демонстрация использования функции в другом программном коде.
// указатели на ref-структуру MyPointRef ^pt1; MyPointRef ^pt2; MyPointRef ^resPt; // выделение памяти для указателей pt1, pt2 pt1 = gcnew MyPointRef; pt2 = gcnew MyPointRef; // заполнение значениями pt1->x = 20; pt1->y = 20; pt2->x = 30; pt2->y = 40; // вызов функции GetCenterLineRef() // память для указателя resPt выделяется внутри функции resPt = GetCenterLineRef(pt1, pt2); // проверка int d; d = resPt->x; // d = 25 d = resPt->y; // d = 30
Связанные темы
- Структуры. Часть 1. Составные типы данных. Шаблон структуры. Структурная переменная. Структуры в среде CLR. Объявление и инициализация структурной переменной
- Структуры. Часть 2. Выделение памяти для структуры. Вложенные структуры. Массивы native-структур
- Структуры. Часть 3. Работа с managed-структурами в среде CLR. Квалификаторы ref и value. Объявление структурных переменных. Массивы managed-структурных переменных. Инициализация managed-структур
- Функции. Часть 1. Описание функции. Фактические и формальные параметры. Передача параметров в функцию по значению и по адресу. Прототип функции
- Функции. Часть 2. Функции и массивы. Передача одномерного и многомерного массива в функцию. Передача структуры и класса в функцию