function - 如何将传递给函数的指针分配给函数

我是C的新手,想知道如何做一些指针的东西。 具体来说,我想知道如何将指针传递给函数,并且"从函数中获取值"。 就像这个( 半伪代码):


assign_value_to_pointer(void* pointer) {


 if (cond1) {


 pointer = 10;


 } else if (cond2) {


 pointer ="foo";


 } else if (cond3) {


 pointer = true;


 } else if (cond4) {


 pointer = somestruct;


 } else if (cond5) {


 pointer = NULL;


 } else if (cond6) {


//unknown type!


 pointer = flexiblearraymember.items[index];


 }


}



main() {


 void* pointer = NULL;



 assign_value_to_pointer(&pointer);



 if (cond1) {


 assert(pointer == 10);


 } else if (cond2) {


 assert(pointer =="foo");


 } else if (cond3) {


 assert(pointer == true);


 } else if (cond4) {


 assert(pointer == somestruct);


 } else if (cond5) {


 assert(pointer == NULL);


 }


}



另一种方法:


p = new Pointer()


assign_a_value(p)


assert(p.value == 10)//or whatever



基本上它是将指针传递给函数,函数是为指针赋值,然后你可以在函数返回时使用该值。 您可能不知道从函数中获得了什么样的值(但可以通过扩展它来使用结构等来处理),因此无效指针。 但主要目标只是将指针传递给某个函数并让它吸收一些值。

想知道如何使用快速示例实现在C中正确执行此操作。 不一定要覆盖所有的情况才能开始。

我想使用它来实现诸如将NULL错误对象传递给函数之类的东西,如果有错误,它会将错误的指针设置为某些错误代码等。

我不认为这应该是一个广泛的问题,但如果是,那么知道在源代码中寻找更全面的解释或示例将会有所帮助。

时间:


void assign_value_to_pointer(int** pointer) {


 **pointer = 20; 


}



void main() {


 void* pointer = NULL;


 pointer=malloc(sizeof(int));


 *(int *)pointer=10;


 assign_value_to_pointer(&pointer);


}



首先,我会直接回答你的问题,希望你明白为什么你需要小心地做。 这可能是实现队列或通信堆栈的有用技术 - 但您需要确保可以重新获得正在存储的类型或程序逻辑将完全中断的跟踪。 然后,我将尝试简要介绍一些用例和一些使其安全的方法。

简单的例子做你所说


#include <stdio.h>


#include <stdlib.h>



//Some basic error type for reporting failures


typedef enum my_error


{


 ERROR_NONE = 0,


 ERROR_FAIL = 1,


} my_error;



struct my_struct


{


 int age;


 char *name;


 int order_count;


};



int someCond = 1;



//Let's start with a simple case, where we know the type of the pointer being passed (an int)


//If int_out is NULL, then this function will invoke undefined behavior (probably a 


//runtime crash, but don't rely on it).


my_error assign_int(int *int_out)


{


 if(someCond)


 *int_out = 5;


 else


 *int_out = 38;



 return ERROR_NONE;


}



//Need to use a 'double pointer', so that this function is actually changing the pointer 


//that exists in the parent scope


my_error dynamically_assign_value_to_pointer(void **pointer)


{


//A pointer internal to this function just to simplify syntax


 void *working_ptr = NULL;



 if(someCond)


 {


//Allocate a region of memory, and store its location in working_ptr


 working_ptr = malloc(sizeof(int));


//store the value 12 at the location that working_ptr points to (using '*' to dereference)


 *((int *) working_ptr) = 12;


 }


 else


 {


//Allocate a region of memory, and store its location in working_ptr


 working_ptr = malloc(sizeof(struct my_struct));


//Fill the struct with data by casting (You can't dereference a void pointer, 


//as the compiler doesn't know what it is.)


 ((struct my_struct *) working_ptr)->age = 22;


 ((struct my_struct *) working_ptr)->name ="Peter";


 ((struct my_struct *) working_ptr)->order_count = 6;


 }



//Set the pointer passed as an argument to point to this data, by setting the 


//once-dereferenced value


 *pointer = working_ptr;



 return ERROR_NONE;


}



int main (int argc, char *argv[])


{


 int an_int;


 void *some_data;



 assign_int(&an_int);



//an_int is now either 5 or 38



 dynamically_assign_value_to_pointer(&some_data);



//some_data now points to either an integer OR a my_struct instance. You will need 


//some way to track this, otherwise the data is useless.


//If you get this wrong, the data will be interpreted as the wrong type, and the 


//severity of the issue depends what you do with it.


//For instance, if you KNOW FOR SURE that the pointer contains the int, you could 


//print it by:


 printf("%d", *((int *) some_data));



//And because it is dynamically allocated, you MUST free it.


 free(some_data);



 return 0;


}



实际上,这对于队列很有用,例如可以编写泛型队列函数,然后为不同的数据类型设置不同的队列。 这是部分代码,所以不能编译,在这种有限的情况下是一个坏主意,当一个类型安全的替代方案设计很简单时,但希望你能得到这个想法:


extern my_queue_type myIntQueue;


extern my_queue_type myStructQueue;



my_error get_from_queue(void *data_out, my_queue_type queue_in);



int main (int argc, char *argv[])


{


//...


 int current_int;


 struct my_struct current_struct;



 get_from_queue(&current_int, myIntQueue);


 get_from_queue(&current_struct, myStructQueue);



//...


}



或者,如果你真的想将许多不同类型的代码一起存储,至少应该在结构中跟踪该类型,以便在必要时适当地转换和处理逻辑,以便正确地处理。 同样,部分示例将不会编译。


enum my_types


{


 MY_INTEGER, MY_DOUBLE, MY_STRUCT


};



struct my_typed_void


{


 void *data;


 enum my_types datatype;


};



my_error get_dynamic_from_global_queue(struct my_typed_void *data_out)


{


//...


 data_out->data = malloc(sizeof int);


 *((int *)(data_out->data)) = 33;


 data_out->datatype = MY_INTEGER;


//...


}



int main (int argc, char *argv[])


{


 struct my_typed_void current;



 if(get_dynamic_from_global_queue(&current) == ERROR_NONE)


 {


 switch(current.datatype)


 {


//...


 case MY_INTEGER:


 printf("%d", *((int *) current.data));


 break;


//...


 }


 free(current.data);


 }



 return 0;


}



返回指针或将指针传递给指针(该函数将更改指针):


void* f1(void* p)


{


 p = whatever(p, conditions);


 return p;


}



void f2(void** p)


{


 *p = whatever(*p, conditions);


}



我不是 100%确定你要找什么,但是它可以能是这样的:


enum pointer_type{INTEGER, STRUCTURE_1, STRUCTURE_2, INVALID};



int assign_value_to_pointer(void ** ptr)


{


 uint8_t cond = getCondition();


 switch(cond)


 {


 case 1:


 *ptr = (void*) 10;


 return INTEGER;


 case 2:


 *ptr = (void*) someStructOfType1;


 return STRUCTURE_1;


 case 3:


 *ptr = (void*) someStructOfType2;


 return STRUCTURE_2;


 default:


 *ptr = NULL;


 return INVALID;


 };


}



void main(void)


{


 void * ptr = NULL;



 int ptrType = assign_value_to_pointer(&ptr);



 switch(ptrType)


 {


 case INTEGER:


 assert(ptr == (void*)10);


 break;


 case STRUCTURE_1:


 assert( ((structType1*) ptr)->thing == something);


 break;


 case STRUCTURE_2:


 assert( ((structType2*) ptr)->something == something);


 break;


 default:


 assert(ptr == NULL);


 }


}



实际上,你可以根据( 状态) 和使用情况在 main() 中输入指针。 但是,在我看来,你可以为此目的使用union 。

创建具有所有可能数据类型的联合。


typedef union _my_union_type_ {


 int intVal;


 char* stringVal;


 bool boolVal;


 SomestructType somestruct;//Assuming you need a structure not structure pointer.


 void* voidPtrType;


} my_union_type;



现在在 main() 中创建这个联合类型的变量并将union的地址传递给函数。


main() {


 my_union_type *my_union= NULL;



 assign_value_to_pointer(&my_union);



 if (cond1) {


 assert(my_union.intVal == 10);


 } else if (cond2) {


 assert(strcmp(my_union.stringVal,"foo"));//String comparison can not be done using '=='


 } else if (cond3) {


 assert(my_union.boolVal == true);


 } else if (cond4) {


 assert(memcmp(&my_union.somestruct, &somestruct, sizeof(somestruct));//Assuming structure not structure pointer.


 } else if (cond5) {


 assert(my_union.voidPtrType == NULL);


 } else if (cond5) {


//Check my_union.voidPtrType


 }


}



在assign_value_to_pointer中,你可以在union变量中存储所需的值。


assign_value_to_pointer(my_union_type* my_union) {


 if (cond1) {


 my_union->intVal = 10;


 } else if (cond2) {


 my_union->stringVal ="foo";


 } else if (cond3) {


 my_union->boolVal = true;


 } else if (cond4) {


 memcpy(&(my_union->somestruct), &somestruct, sizeof(somestruct));


 } else if (cond5) {


 my_union->voidPtrType = NULL;


 } else if (cond6) {


//unknown type!


 my_union->voidPtrType = flexiblearraymember.items[index];


 }


}



你离成功并不遥远,你只需要一个星号来取消引用这个:


void assign_value_to_pointer(void* pointer) {


 if (cond1) {


 *pointer = 10;//note the asterisk


. . .


}



void main() {


 void* pointer = NULL;



 assign_value_to_pointer(&pointer);



}



在C 语言中,函数的参数总是通过值传递。 如果希望函数修改参数,则必须传递要修改的变量的地址。 在main()中,你正在这样做 - 正确。 被调用的函数可以写入其参数所指向的位置,从而修改原始变量;要做到这一点,你必须取消引用这个论点。

编译器应该对赋值感到生气,因为它不知道要写多少字节(我保持简单)。 因此,你必须说明指针指向的对象类型,如下所示:


*(int *) pointer = 10;



你选择的角色取决于你,它取决于上下文。

此时......为什么不以不同方式声明函数:


void assign_value_to_pointer(int* pointer) {


 if (cond1) {


 *pointer = 10;//note the asterisk


}



因为编译器知道对象( 我又要保持简单- void 非常特殊)的类型,所以这个角色不再是必需的了。

注释后的******* 编辑

好吧,我不是C语言的大师,而且,我想保持低调,以更好地帮助OP。

对于简单的情况,正确的声明是幼稚的。 类型转换可以更灵活,因为该函数可以根据上下文选择多个赋值语句。 最后,如果函数传递了指针和其他参数,则一切都是可能的,包括使用 memcpy() 。 但这最后的解决方案打开了一个世界......

...