ถ้าฉันมีฟังก์ชันที่สร้างผลลัพธ์int
และผลลัพธ์string
ฉันจะคืนค่าทั้งสองจากฟังก์ชันได้อย่างไร
เท่าที่ฉันสามารถบอกได้ว่าฉันสามารถคืนค่าได้เพียงสิ่งเดียวเท่านั้นตามที่กำหนดโดยประเภทที่อยู่ข้างหน้าชื่อฟังก์ชัน
ถ้าฉันมีฟังก์ชันที่สร้างผลลัพธ์int
และผลลัพธ์string
ฉันจะคืนค่าทั้งสองจากฟังก์ชันได้อย่างไร
เท่าที่ฉันสามารถบอกได้ว่าฉันสามารถคืนค่าได้เพียงสิ่งเดียวเท่านั้นตามที่กำหนดโดยประเภทที่อยู่ข้างหน้าชื่อฟังก์ชัน
คำตอบ:
ฉันไม่รู้ว่าคุณstring
คืออะไรแต่ฉันจะสมมติว่ามันจัดการหน่วยความจำของมันเอง
คุณมีสองวิธีแก้ไข:
1: ส่งคืน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 *
และsize_t
สำหรับความยาวเว้นแต่มันเป็นความสำคัญอย่างยิ่งสำหรับการทำงานในการจัดสรรก็สตริงเองและ / NULL
หรือผลตอบแทน
getPair
แล้วdereferences ขึ้นอยู่กับสิ่งที่คุณกำลังทำอยู่ (OP ไม่เคยชี้แจงว่านี่เป็นคำถาม C จริงหรือไม่) การจัดสรรอาจเป็นสิ่งที่น่ากังวล แต่โดยปกติแล้วจะไม่อยู่ในที่ดิน C ++ (การเพิ่มประสิทธิภาพการคืนค่าจะบันทึกสิ่งเหล่านี้ทั้งหมด) และในที่ดิน C ข้อมูล สำเนามักจะเกิดขึ้นอย่างชัดเจน (ผ่านทางstrncpy
หรืออะไรก็ตาม)
Option 1
: ประกาศโครงสร้างด้วย int และสตริงและส่งคืนตัวแปร 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 ++ ...
สร้างโครงสร้างและตั้งค่าสองค่าภายในและส่งคืนตัวแปร struct
struct result {
int a;
char *string;
}
คุณต้องจัดสรรพื้นที่สำหรับchar *
ในโปรแกรมของคุณ
ใช้พอยน์เตอร์เป็นพารามิเตอร์ฟังก์ชันของคุณ จากนั้นใช้เพื่อคืนค่าหลายค่า
โดยส่งผ่านพารามิเตอร์โดยอ้างอิงถึงฟังก์ชัน
ตัวอย่าง:
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)
โซลูชันนี้อาจไม่สามารถพกพาได้เนื่องจากต้องใช้ C99 หรือใหม่กว่าสำหรับแมโครตัวแปรและการประกาศตัวแปรสำหรับคำสั่ง แต่ฉันคิดว่ามันน่าสนใจพอที่จะโพสต์ที่นี่ ปัญหาอีกประการหนึ่งคือคอมไพลเลอร์จะไม่เตือนคุณหากคุณกำหนดค่าที่ไม่ถูกต้องดังนั้นคุณต้องระวัง
ตัวอย่างเพิ่มเติมและรุ่นสแต็คที่ใช้ในการใช้รหัสสหภาพแรงงานมีที่ของฉันที่เก็บ GitHub
__typeof__
string
คุณหมายความว่า "ฉันใช้ C ++ และนี่คือstd::string
ระดับ" หรือ "ฉันใช้ C และนี่คือchar *
ตัวชี้หรือchar[]
อาร์เรย์."