[英]Is there a way I can pass a struct variable as an argument to a function? (C)
[英]How can I pass a generic struct to a function in C?
我是C編程的初學者,我對將通用結構傳遞給C中的函數有疑問。
這是我所擁有的:
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
我想做這樣的事情:
void changeName(struct *s, newName[20]) {
strcpy(s->name, newName);
}
如果有人已經問過了,請不要理會,並向我發送問題鏈接。
有人可以幫我嗎?
謝謝。
union
一種方法是添加一個包含union
的結構,該union
本身包含指向product
和category
結構的指針,以及一個enum
以標識struct
的數據類型。 該union
或指向它的指針可以傳遞給change_name()
函數。
這是在C11中可以使用的示例。 它使用一個未命名的union
成員,因此這不是有效的C99代碼:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
product *prod;
category *cat;
};
} generic;
void change_name(generic *gen, const char *new_name);
int main(void)
{
product prod_a = { .name = "widget", .price = 1.99 };
category cat_a = { .name = "general", .type = 1 };
generic gen_prod_a = { .type = PRODUCT, .prod = &prod_a };
generic gen_cat_a = { .type = CATEGORY, .cat = &cat_a };
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
change_name(&gen_prod_a, "gadget");
change_name(&gen_cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
return 0;
}
void change_name(generic *gen, const char *new_name)
{
switch (gen->type) {
case PRODUCT:
strcpy(gen->prod->name, new_name);
break;
case CATEGORY:
strcpy(gen->cat->name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
可以通過命名union
使它在C99中起作用:
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
product *prod;
category *cat;
} data; // named for C99
} generic;
/* ... */
generic gen_prod_a = { .type = PRODUCT, .data.prod = &prod_a };
generic gen_cat_a = { .type = CATEGORY, .data.cat = &cat_a };
/* ... */
void change_name(generic *gen, const char *new_name)
{
switch (gen->type) {
case PRODUCT:
strcpy(gen->data.prod->name, new_name);
break;
case CATEGORY:
strcpy(gen->data.cat->name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
可替代地,一個struct
類型可以容納一個enum
標識符和union
含有產物和類結構。 這種方法似乎更加簡化:
#include <stdio.h>
#include <string.h>
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
struct {
char name[20];
float price;
} prod;
struct {
char name[20];
int type;
} cat;
} data;
} record;
void change_name(record *rec, const char *new_name);
int main(void)
{
record prod_a = { .type = PRODUCT };
change_name(&prod_a, "widget");
prod_a.data.prod.price = 1.99;
record cat_a = { .type = CATEGORY };
change_name(&cat_a, "general");
cat_a.data.cat.type = 1;
printf("prod_a.name = %s\n", prod_a.data.prod.name);
printf("cat_a.name = %s\n", cat_a.data.cat.name);
change_name(&prod_a, "gadget");
change_name(&cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.data.prod.name);
printf("cat_a.name = %s\n", cat_a.data.cat.name);
return 0;
}
void change_name(record *rec, const char *new_name)
{
switch (rec->type) {
case PRODUCT:
strcpy(rec->data.prod.name, new_name);
break;
case CATEGORY:
strcpy(rec->data.cat.name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
以上兩種方法都有些尷尬。 僅適用於C11的另一種解決方案是在類型通用宏中使用_Generic
關鍵字。 在此,為每種期望的數據類型編寫函數,並且宏根據類型選擇要使用的函數定義。 這種方法的優點是,隨着添加新類型,只需新函數和對類型通用宏的更新即可處理它們。
#include <stdio.h>
#include <string.h>
#define change_name(S, N) _Generic ((S), \
prod_ptr: change_name_prod, \
cat_ptr: change_name_cat \
)((S), (N))
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
typedef product *prod_ptr;
typedef category *cat_ptr;
void change_name_prod(product *prod, const char *new_name);
void change_name_cat(category *cat, const char *new_name);
int main(void)
{
product prod_a = { .name = "widget", .price = 1.99 };
category cat_a = { .name = "general", .type = 1 };
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
change_name(&prod_a, "gadget");
change_name(&cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
return 0;
}
void change_name_prod(product *prod, const char *new_name)
{
strcpy(prod->name, new_name);
}
void change_name_cat(category *cat, const char *new_name)
{
strcpy(cat->name, new_name);
}
以上所有程序都具有相同的輸出:
prod_a.name = widget
cat_a.name = general
prod_a.name = gadget
cat_a.name = specific
您已經對結構進行了類型定義。 您可以使用這些其他名稱。
例如,如果名稱為product
,則首先創建一個變量並調用該函數
product var={"name", 1.2};
changeName(&var, "AnotherName");
然后將此變量傳遞給函數
void changeName(product *s, char newName[])
{
strcpy(s->name, newName);
}
泛型編程,這意味着C語言中實際上並不存在類型安全性。但是有很多方法可以解決這種情況。
我從您的問題中了解到的是,“我可以定義一個可以應用於不同結構的通用元素的函數嗎?
讓我們擴展一下示例,以具有共同特征的項目。
struct info
{
char name[20];
int id;
};
struct product
{
Info info;
int price;
};
struct category
{
Info info;
int type;
};
現在,您可以定義一個可以在產品和類別共享的特征上安全運行的函數。
void changeName(info* p, const char* name)
{
strcpy_s(info->name, sizeof(info->name), name);
}
int main()
{
category cat;
product prod;
memset(&cat, 0, sizeof(cat));
memset(&prod, 0, sizeof(prod));
changeName(&cat.info, "Category 1");
changeName(&prod.info, "blue product");
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.