Якщо у мене є функція, яка видає результат int
і результат string
, як повернути їх обох із функції?
Наскільки я можу сказати, я можу повернути лише одне, що визначається типом, що передує імені функції.
Якщо у мене є функція, яка видає результат int
і результат string
, як повернути їх обох із функції?
Наскільки я можу сказати, я можу повернути лише одне, що визначається типом, що передує імені функції.
Відповіді:
Я не знаю, що ти string
такий, але я збираюся припустити, що він керує власною пам'яттю.
У вас є два рішення:
1: Поверніть a, struct
який містить усі потрібні типи.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Використовуйте покажчики для передачі значень.
void getPair(int* a, string* b) {
// Check that these are not pointing to NULL
assert(a);
assert(b);
*a = 1;
*b = getString();
}
void foo() {
int a, b;
getPair(&a, &b);
}
Який із них ви вирішите використовувати, багато в чому залежить від особистих уподобань щодо будь-якої семантики, яка вам подобається більше.
char *
та a size_t
для довжини, якщо функція не має абсолютно важливого значення для виділення власного рядка та / або повернення NULL
.
getPair
потім здійснює розмежування . Залежно від того, що ви робите (OP ніколи не уточнював, чи це насправді питання C), розподіл може викликати занепокоєння, але, як правило, це не в C ++ land (оптимізація поверненого значення все це економить) і в C land, дані копії, як правило, трапляються явно (через strncpy
чи інше).
Option 1
: Оголосіть структуру за допомогою int та string та поверніть змінну struct.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2
: Ви можете передати один із двох через покажчик і внести зміни до фактичного параметра через покажчик, а другий повернути як зазвичай:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
або
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3
: Подібно до варіанту 2. Ви можете передавати як через покажчик, так і нічого не повертати з функції:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
int fun(char *param, size_t len)
strcpy
наприклад.
Оскільки одним із типів результатів є рядок (і ви використовуєте C, а не C ++), я рекомендую передавати покажчики як вихідні параметри. Використання:
void foo(int *a, char *s, int size);
і назвіть це так:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
Загалом, віддайте перевагу розподілу у функції, що викликає , а не всередині самої функції, щоб ви могли бути максимально відкритими для різних стратегій розподілу.
Два різних підходи:
Я думаю, що №1 трохи очевидніше про те, що відбувається, хоча це може стати нудним, якщо у вас занадто багато повернутих значень. У цьому випадку варіант №2 працює досить добре, хоча для створення спеціалізованих конструкцій для цієї мети задіяні певні розумові витрати.
string
, можливо, можна вважати C ++ ...
Передаючи параметри за посиланням на функцію.
Приклади:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Також за допомогою глобальних змінних, але це не рекомендується.
Приклад:
int a=0;
void main(void)
{
//Anything you want to code.
}
void main(void)
О, ЯК ЦЕ ЗГАРЕ!
main
повинен повертати код стану. Під * nix звичайніше оголошувати це як int main(int argc, char *argv[])
, я вважаю, Windows має подібні домовленості.
Один із підходів - використання макросів. Помістіть це у файл заголовкаmultitype.h
#include <stdlib.h>
/* ============================= HELPER MACROS ============================= */
/* __typeof__(V) abbreviation */
#define TOF(V) __typeof__(V)
/* Expand variables list to list of typeof and variable names */
#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1) TOF(_0) v0; TOF(_1) v1;
#define TO0(_0) TOF(_0) v0;
#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO
#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)
/* Assign to multitype */
#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1) _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0) _0 = mtr.v0;
#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO
#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)
/* Return multitype if multiple arguments, return normally if only one */
#define MTR1(...) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t *mtr = malloc(sizeof(mtr_t)); \
*mtr = (mtr_t){__VA_ARGS__}; \
return mtr; \
}
#define MTR0(_0) return(_0)
#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO
/* ============================== API MACROS =============================== */
/* Declare return type before function */
typedef void* multitype;
#define multitype(...) multitype
/* Assign return values to variables */
#define let(...) \
for(int mti = 0; !mti;) \
for(multitype mt; mti < 2; mti++) \
if(mti) { \
typedef struct mtr_s { \
TO(__VA_ARGS__) \
} mtr_t; \
mtr_t mtr = *(mtr_t*)mt; \
MTA(__VA_ARGS__) \
free(mt); \
} else \
mt
/* Return */
#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)
Це дає можливість повернути до чотирьох змінних із функції та призначити їх до чотирьох змінних. Як приклад, ви можете використовувати їх так:
multitype (int,float,double) fun() {
int a = 55;
float b = 3.9;
double c = 24.15;
RETURN (a,b,c);
}
int main(int argc, char *argv[]) {
int x;
float y;
double z;
let (x,y,z) = fun();
printf("(%d, %f, %g\n)", x, y, z);
return 0;
}
Ось що друкується:
(55, 3.9, 24.15)
Рішення може бути не таким портативним, оскільки для варіативних макросів та оголошень змінних for-statement потрібен C99 або новішої версії. Але я думаю, що це було досить цікаво розміщувати тут. Інша проблема полягає в тому, що компілятор не попередить вас, якщо ви призначите їм неправильні значення, тому вам слід бути обережними.
Додаткові приклади та версія коду на основі стеку за допомогою профспілок доступні в моєму сховищі github .
__typeof__
string
цим ви маєте на увазі "я використовую С ++ і цеstd::string
клас" або "я використовую С, а цеchar *
вказівник абоchar[]
масив".