Nếu tôi có một hàm tạo ra một kết quả int
và một kết quả string
, làm cách nào để trả về cả hai từ một hàm?
Theo như tôi có thể nói, tôi chỉ có thể trả về một thứ, được xác định bởi kiểu đứng trước tên hàm.
Nếu tôi có một hàm tạo ra một kết quả int
và một kết quả string
, làm cách nào để trả về cả hai từ một hàm?
Theo như tôi có thể nói, tôi chỉ có thể trả về một thứ, được xác định bởi kiểu đứng trước tên hàm.
Câu trả lời:
Tôi không biết của bạn string
là gì , nhưng tôi sẽ giả định rằng nó quản lý bộ nhớ của chính nó.
Bạn có hai giải pháp:
1: Trả về a struct
chứa tất cả các loại bạn cần.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Sử dụng con trỏ để chuyển giá trị.
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);
}
Việc bạn chọn sử dụng cái nào phụ thuộc phần lớn vào sở thích cá nhân về bất kỳ ngữ nghĩa nào bạn thích hơn.
char *
và a size_t
cho độ dài trừ khi nó thực sự quan trọng để hàm cấp phát chuỗi và / hoặc trả về của chính nó NULL
.
getPair
sau đó sẽ bỏ tham chiếu . Tùy thuộc vào những gì bạn đang làm (OP không bao giờ làm rõ nếu đây thực sự là một câu hỏi C), phân bổ có thể là một mối quan tâm, nhưng nó thường không phải trong đất C ++ (tối ưu hóa giá trị trả về tiết kiệm tất cả điều này) và trong C đất, dữ liệu các bản sao thường diễn ra rõ ràng (thông qua strncpy
hoặc bất cứ điều gì).
Option 1
: Khai báo một cấu trúc với một int và chuỗi và trả về một biến cấu trúc.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2
: Bạn có thể chuyển một trong hai thông qua con trỏ và thực hiện các thay đổi đối với tham số thực tế thông qua con trỏ và trả về tham số kia như bình thường:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
hoặc là
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3
: Tương tự như tùy chọn 2. Bạn có thể chuyển cả hai thông qua con trỏ và không trả về gì từ hàm:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
int fun(char *param, size_t len)
strcpy
chẳng hạn.
Vì một trong các loại kết quả của bạn là chuỗi (và bạn đang sử dụng C, không phải C ++), tôi khuyên bạn nên chuyển con trỏ làm tham số đầu ra. Sử dụng:
void foo(int *a, char *s, int size);
và gọi nó như thế này:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
Nói chung, bạn nên thực hiện phân bổ trong hàm đang gọi , không phải bên trong chính hàm, để bạn có thể cởi mở nhất có thể cho các chiến lược phân bổ khác nhau.
Hai cách tiếp cận khác nhau:
Tôi nghĩ rằng số 1 rõ ràng hơn một chút về những gì đang xảy ra, mặc dù nó có thể trở nên tẻ nhạt nếu bạn có quá nhiều giá trị trả về. Trong trường hợp đó, tùy chọn số 2 hoạt động khá tốt, mặc dù có một số chi phí tinh thần liên quan đến việc tạo các cấu trúc chuyên biệt cho mục đích này.
string
, nó có thể là an toàn để giả định C ++ ...
Bằng cách truyền các tham số bằng tham chiếu đến hàm.
Ví dụ:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Cũng bằng cách sử dụng các biến toàn cục nhưng nó không được khuyến khích.
Thí dụ:
int a=0;
void main(void)
{
//Anything you want to code.
}
void main(void)
OH LÀM THẾ NÀO RỒI!
main
phải trả về một mã trạng thái. Dưới * nix, thông thường hơn là khai báo nó int main(int argc, char *argv[])
, tôi tin rằng Windows có các quy ước tương tự.
Một cách tiếp cận là sử dụng macro. Đặt cái này vào một tệp tiêu đề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__)
Điều này giúp bạn có thể trả về tối đa bốn biến từ một hàm và gán chúng cho tối đa bốn biến. Ví dụ, bạn có thể sử dụng chúng như sau:
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;
}
Đây là những gì nó in:
(55, 3.9, 24.15)
Giải pháp có thể không khả thi vì nó yêu cầu C99 trở lên cho các macro đa dạng và khai báo biến for-statement. Nhưng tôi nghĩ rằng nó đã đủ thú vị để đăng ở đây. Một vấn đề khác là trình biên dịch sẽ không cảnh báo bạn nếu bạn gán giá trị sai cho chúng, vì vậy bạn phải cẩn thận.
Các ví dụ bổ sung và phiên bản mã dựa trên ngăn xếp bằng cách sử dụng công đoàn, có sẵn tại kho lưu trữ github của tôi .
__typeof__
string
bạn là "Tôi đang sử dụng C ++ và đây làstd::string
lớp" hoặc "Tôi đang sử dụng C và đây là mộtchar *
con trỏ hoặcchar[]
mảng."