需要解释我们应该在哪些场合使用 &with printf 在 C 语言中



据我所知,在c中使用printf()时我们不使用&.右?但是在我的程序中,如果我不在显示功能中使用它,它会给我一个错误。有人可以解释一下吗?谢谢

#include<stdio.h>
#define max 100
void enqueue();
char dequeue(void);
int front=-1,rear=-1,option;
char name[max][max],val;
void display(void);

void enqueue() {
printf("Enter the name of the paitent : ");
if(rear==max-1)
printf("Line is full");
else if (front==-1 && rear==-1)
front=rear=0;
else
rear++;
scanf("%s",&name[rear][rear]);
}
char dequeue(void) {
char val;
if(front==-1 || front >rear )
printf("Line is empty");
else
{
val=name[front];
front++;
if(front>rear)
front=rear=-1;
return val;
}
}
void display(void) {
int i;
if(front==-1|| front >rear)
printf("The queue is empty");
else
{
for(i=front; i<=rear; i++) {
printf("%st",&name[i][i]);
}
}
}

int main () {
printf("nn*******Medical Cneter********");
printf("nt1. Insert a paitent");
printf("nt2. Remove a paitent");
printf("nt3. Check Paitent list");
printf("nt4. Display");
printf("nt5. Exit");
do {
printf("nEnter your option: ");
scanf("%d",&option);
switch(option) 
{
case 1:
enqueue();
break;
case 2:
dequeue();
break;
//  case 3:
case 4:
display();
break;
}
} while(option !=5);
}

如果我不使用,程序就会崩溃。据我所知,在 c 中使用printf()时我们不使用。但是在我的程序中,如果我不在显示功能中使用它,它会给我一个错误。有人可以解释一下吗?谢谢

为了回答您的问题,让我们回顾一下&运算符的作用,以及我们需要传递给printf哪些类型的值,以及为了进行比较,我们需要传递给scanf哪些类型的值。

如果你有一个x的东西,那么表达式&x会给你一个指向x的指针。 如果x是一个int&x给出一个指向int的指针。 如果x是一个char&x给出指向char的指针。

例如,如果我写

int i;
int *ip;
ip = &i;

我已经声明了一个int变量i,以及一个指向整数的指针变量ip。 我使用&运算符制作了一个指向i的指针,并将该指针int存储在变量ip中。 这都很好。

如您所知,当您调用scanf时,您始终必须传递指向您希望scanf为您填写的变量的指针。 你不能写

scanf("%d %d", x, y);    /* WRONG */

因为这会将变量的值传递给xyscanf. 但是您不想将值传递给scanf,您希望scanf从用户那里读取一些值,并将它们传输回给您。 实际上,您希望scanf写入变量xy。 这就是为什么您将指针传递给xy,以便scanf可以使用指针来填充变量。 所以这就是为什么你几乎总是在scanf调用中看到&的参数。

但这些原因都不适用于printf。 当你调用printf时,你确实希望将普通值传递给它。 您(通常)不会要求printf将任何数据传回给您。 因此,大多数printf格式说明符被定义为接受普通值,而不是指向值的指针。 所以这就是为什么你几乎不会在printf通话中看到&

现在,您可能会认为&是将事物"转换为"指针的运算符,但这并不是一种很好的思考方式。 正如我所说,给定一个对象x,表达式&x构造一个指向x的指针。 它不会"转换"任何东西;它当然不会"转换"X。 它构造一个全新的指针值,指向x

在您发布的代码中,看起来您可能已经使用了&来尝试执行此类"转换"。 您有一个数组name类型为数组数组的数组char,或者一个二维字符数组。 您正在尝试打印带有%s的字符串。 您知道,或者您的编译器警告您,%s需要一个指向字符的指针,并且您知道(或您的编译器告诉您)表达式name[i][i]给出了类型char的值。 现在,将&放在name[i][i]前面确实得到了一个类型的值 指针指向char,正如%s所要求的那样,它甚至可能看起来有效,但这是一个非常随意的解决方案。

的确,printf%s需要一个指向char的指针,但它不需要任何指向char的指针;它需要一个指向一个有效的、以 null 结尾的字符串的指针到char。 这就是为什么,即使%s需要一个指针,你仍然不会在printf调用中看到&。 您可以在单个字符变量上使用&来获取指向该字符的指针,如下所示:

char c = 'x';
printf("%s", &c);    /* WRONG */

但这是损坏的代码,无法正常工作,因为您获得的指针不是有效的字符串,因为没有 null 终止。

在您的代码中,您可能希望更改该行

printf("%st",&name[i][i]);

printf("%st",name[i]);

name是一个二维的char数组,但由于 C 中的字符串是char数组,你也可以将name视为一个(单维)字符串数组,我认为这就是你尝试使用它的方式。

同样,我怀疑您想更改行

scanf("%s",&name[rear][rear]);

scanf("%s", name[rear]);

但在你说"我以为scanf总是需要&!"之前,请记住,规则是scanf需要一个指针。 由于name[i]是一个数组,因此当您将其传递给scanf时(或者实际上,当您在任何表达式中使用它时),您会自动获得指向其第一个元素的指针。 (这也是printf("%st",name[i])背后的原因。

如果你想使用显式&,你想要的是一个指向你想要scanf填充的字符串数组开头的指针,所以我想你会想要

scanf("%s", &name[rear][0]);

而不是你的表情。

(看起来您可能不小心将字符串沿着name数组的对角线运行,而不是沿着左边缘运行。 也很奇怪你声明了完美方形数组

char name[max][max];

即 100 个字符串,每个字符串 100 个字符。 这没有错,它会起作用,但它很好奇,它更容易混淆行和列。

'

我尝试编译您的代码,但似乎出现错误:

warning: assignment makes integer from pointer without a cast [-Wint-conversion]
val=name[front];
^

原因是name是一个 2D 数组,并且您正在将指向 char 字符的一维数组的指针分配给一个 char。

我认为,为了完全理解这个问题,人们必须理解C如何处理内存和指针。

"&"符号表示您正在获取某物的地址(不要与 c++ 引用混淆)。

这意味着,如果函数具有如下所示的参数:

void foo(char* bar);

如果要将变量char var;传递给函数,则必须使用"&"符号调用函数,以显式告诉编译器要将var的地址作为参数传递给函数。

foo(&var);

如果要访问函数foo中的var值,则必须"取消引用"指针,以便编译器理解您希望将值存储在刚刚传递给函数的地址处。

要取消引用指针,请使用"*"符号。

char some_char_in_foo = *var;

我建议阅读指针以进一步澄清此事。

printfscanf中的%s转换说明符都希望其对应的参数具有类型char *,并指向字符串中的第一个字符。

请记住,在 C 中,字符串是包含 0 值终止符的字符序列。 字符串存储在char数组中(对于"宽"字符串,则存储wchar_t数组)。

您的name数组可以存储max个字符串,每个字符串最多可以存储max-1 个字符,这还不包括字符串终止符。

当数组表达式不是sizeof或一&元运算符的操作数,或者不是用于初始化声明中的字符数组的字符串文本时,表达式将隐式转换("衰减")从类型"char数组"转换为"指向char的指针",并且表达式的值是第一个元素的地址。

name的类型是"max元素数组maxchar元素数组"。 这意味着每个name[i]都有类型"maxchar元素数组",如果不是&sizeof的操作数,则"衰减"为char *类型。

这基本上是一种冗长的说法,即表达式max[i]等同于&max[i][0]。 因此,您可以将printf语句编写为

printf( "%st", name[i] ); 

同样,您可以将enqueue函数中的scanf语句重写为

scanf( "%s", name[i] ); 

虽然老实说,对于用户输入,使用fgets更安全:

if ( fgets( name[i], sizeof name[i], stdin ) )
// successful input
else
// EOF or error on read

&运算符的意思是"获取引用"。scanf修改其参数,因此,您需要提供对要修改的参数的引用。printf不会修改其参数,因此,您可以按值传递其参数,因为它可以使用副本完成其工作。

但是,这不是最终规则,因为格式字符串%p将打印指针(即引用)。因此,在某些情况下,printf可能需要对变量的引用。

一个更一般的规则是这样的:scanf通过引用获取其参数,printf通过值获取其参数。

最新更新