据我所知,在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 */
因为这会将变量的值传递给x
和y
scanf
. 但是您不想将值传递给scanf
,您希望scanf
从用户那里读取一些值,并将它们传输回给您。 实际上,您希望scanf
写入变量x
和y
。 这就是为什么您将指针传递给x
和y
,以便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;
我建议阅读指针以进一步澄清此事。
printf
和scanf
中的%s
转换说明符都希望其对应的参数具有类型char *
,并指向字符串中的第一个字符。
请记住,在 C 中,字符串是包含 0 值终止符的字符序列。 字符串存储在char
数组中(对于"宽"字符串,则存储wchar_t
数组)。
您的name
数组可以存储max
个字符串,每个字符串最多可以存储max
-1 个字符,这还不包括字符串终止符。
当数组表达式不是sizeof
或一&
元运算符的操作数,或者不是用于初始化声明中的字符数组的字符串文本时,表达式将隐式转换("衰减")从类型"char
数组"转换为"指向char
的指针",并且表达式的值是第一个元素的地址。
name
的类型是"max
元素数组max
char
元素数组"。 这意味着每个name[i]
都有类型"max
char
元素数组",如果不是&
或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
通过值获取其参数。