我真的不明白指针的指针是如何工作的。没有使用指向指针的任何方法做同样的工作?
struct customer
{
char name[20];
char surname[20];
int code;
float money;
};
typedef struct customer customer;
void inserts(customer **tmp)
{
*tmp = (customer *)malloc(sizeof(customer));
puts("Give me a customer name, surname code and money");
scanf("%s %s %d %f", (*tmp)->name, (*tmp)->surname, &(*tmp)->code, &(*tmp)->money);
}
答案 0 :(得分:6)
指针101的指针
假设您有一个int
变量x
:int x;
。
printf("x's memory address = %p\n", &x);
printf("x=%d\n", x);
x = 42;
x
),则该函数不能操作`x`的值。&x
),该函数可以操作`x`的值。现在,假设您有一个指针变量p
,假定它指向int
:int *p;
printf("p's memory addr = %p\n", &p
printf("Address where `p` is pointing: %p\n", p);
printf("int = %d\n", *p);
p = &x
p = &x;
或p = NULL
p
),则该函数无法操纵'p'来改变它指向的位置。&p
),该函数可以操作`p`指向的内容。现在,假设你有一个指针变量pp
的指针,它假定它指向一个指向'int'的指针:int **pp;
...或:void inserts(customer ** tmp ):
回到问题
问:没有使用指向指针的方法可以做同样的工作吗?
没有。假设如下:
void inserts(customer **tmp);
...
{
customer cust;
custPtr custPtr = &cust;
inserts(&custPtr);
...
inserts()
函数需要指针的地址才能操纵custPtr
点的位置。
如果相反:
void inserts2(customer *tmp);
...
{
customer cust;
custPtr custPtr = &cust;
inserts2(custPtr);
...
insert2()
会获得custPtr
值的副本,即cust
的地址。因此,insert2()
可以修改cust
的值,但无法更改custPtr
指向的位置。
答案 1 :(得分:4)
对于T
类型的任何参数,如果要修改参数的值并在调用者中反映该更改,则必须传递指针:
void foo( T *ptr )
{
*ptr = new_value();
}
void bar( void )
{
T var;
foo( &var ); // writes to var
}
如果T
是一个指针类型Q *
,那么你最终会得到一个指向指针的指针:
void foo( Q **ptr )
{
*ptr = new_value();
}
void bar( void )
{
Q *var;
foo( &var ); // writes to var
}
你可以使用typedef来隐藏变量的指针,但是根据我的经验,隐藏在typedef后面的指针是糟糕的juju。
您可以更改函数以返回指针值,而不是写入参数,正如@Namfuak建议的那样:
Q *foo( void )
{
Q *val = new_value();
return val;
}
void bar( void )
{
Q *var;
var = foo();
}
答案 2 :(得分:0)
如果指针是您的电话簿条目,则可以将指向该指针的指针告知您存在该条目的电话簿。
查看您的代码:
struct customer {
char name[20];
char surname[20];
int code;
float money;
};
首先,you should not use a float type for money。
您的问题与C FAQ 4.8有关。基本上,您具有插入客户记录的功能。你想在哪里插入记录?显而易见的东西,电话簿,数据库等等。所以,你需要的是一个指向某个东西的指针,指针指向你要插入的对象的指针。
现在,至于您的其余代码,首先请注意you should not cast the return value of malloc
。第二,using scanf
is a serious security risk。第三,您在inserts
函数中分配了一个新的客户记录,但是您无法将任何故障传达给调用您的函数的代码。
可以说,函数的名称应该类似于create_customer_interactive
,以表明它不仅仅是在记录列表中插入记录。
以下是构建代码的方法:
#include <stdio.h>
#include <stdlib.h>
struct customer {
char *name;
char *surname;
int code;
int money; /* in cents */
};
typedef struct customer *PCustomer;
int read_customer_record(FILE *fp, PCustomer customer) {
/* dummy implementation */
customer->name = "A. Tester";
customer->surname = "McDonald";
customer->code = 123;
customer->money = 100 * 100;
return 1;
}
PCustomer insert_record_interactive(PCustomer *db, FILE *fp) {
PCustomer tmp = malloc(sizeof(*tmp));
if (!tmp) {
return NULL;
}
if (!read_customer_record(fp, tmp)) {
free(tmp);
return NULL;
}
*db = tmp;
return tmp;
}
int main(void) {
PCustomer new_customer;
PCustomer *db = malloc(3 * sizeof(*db));
if (!db) {
perror("Failed to allocate room for customer records");
exit(EXIT_FAILURE);
}
/* insert a record in the second slot */
new_customer = insert_record_interactive(&db[1], stdin);
if (!new_customer) {
perror("Failed to read customer record");
exit(EXIT_FAILURE);
}
printf(
"%s %s (%d) : $%.2f\n",
new_customer->name,
new_customer->surname,
new_customer->code,
((double)new_customer->money) / 100.0
);
return 0;
}
答案 3 :(得分:0)
多个间接级别可能会导致混淆。一个好的策略是通过降低间接水平来减少混淆。
关于使用scanf()
的合法担忧,以下是实现此目的的方法:
void inserts(customer **tmp)
{
customer *new_cust = malloc(sizeof *new_cust);
if ( !new_cust ) {
fprintf(stderr, "Couldn't allocate memory.\n");
exit(EXIT_FAILURE);
}
puts("Give me a customer name, surname code and money");
scanf("%s %s %d %f", new_cust->name, new_cust->surname,
new_cust->code, new_cust->money);
/* We delay using multiple levels of indirection
until we get to the very last line, here. */
*tmp = new_cust;
}
正如其他人所提到的,在这种特殊情况下,只返回指针可能会更容易。
答案 4 :(得分:-2)
void inserts(customer *tmp[])
{
*tmp = malloc(sizeof(customer));
puts("Give me a customer name, surname code and money");
scanf("%s %s %d %f", (*tmp)->name, (*tmp)->surname, &(*tmp)->code, &(*tmp)->money);
}
这相当于。指向指针的指针也可以表示为指向未知大小数组的指针。
* tmp被分配给1个“customer”类型元素的数组。 tmp本身以两种方式(** tmp和* tmp [])指向未知大小的“customer”元素数组的指针。