c语言中带指针程序的输出

c语言中带指针程序的输出,c,pointers,C,Pointers,我是c的新手。在执行程序的过程中,第一个输出显示结果为z,第二个输出显示15,但在初始化为long时无法显示结果。有人能解释为什么吗 main() { char c,*cc; int i; long k; k=9999; c='z'; i=15; cc=&c; printf("%c,%u",*cc,cc); cc=&i; printf("\n%d,%u",*cc,cc); cc=&k

我是c的新手。在执行程序的过程中,第一个输出显示结果为z,第二个输出显示15,但在初始化为long时无法显示结果。有人能解释为什么吗

main()
{
    char c,*cc;
    int i;
    long k;
    k=9999;
    c='z';
    i=15;
    cc=&c;
    printf("%c,%u",*cc,cc); 
    cc=&i;
    printf("\n%d,%u",*cc,cc);
    cc=&k;
    printf("\n%ld,%u",*cc,cc);
}

简单的答案是,您正在调用未指定的行为

一个较长的答案是:

因为,在您的系统上,指针与
int
一样大,但小于
long

第一次打印F:

*cc
升级为
int
char
short
用作变量args时升级为
int

Printf
将其打印为
char
并按预期显示
z

第二次打印F:

*cc
指向
i
中的第一个字节。它被提升为
int
char
short
在用作var args时被提升为
int
)。由于它打印15(而不是0),我们可以看出您的系统是

第三次印刷f:

*cc
指向
k
中的第一个字节。由于您使用的是小端系统,因此计算结果为15(9999=15+39*2^8)。它被提升为
int
char
short
在用作var args时被提升为
int

但是,您提供了格式说明符
%ld
,它需要很长的时间。我的猜测是,在您的系统上,long是int的两倍,这意味着它将打印指针值加上15,这将导致一些大的数字

第二个printf说明符将获取当前堆栈帧外的4个字节(假设
int
为32位),这将打印(可能不是这样)随机数,或者可能导致分段错误

注:

我对您的系统做了一些假设:

8位字符/字节

32位整数

32位指针


64位长

您的程序将
cc
声明为指向
char
的指针。当使用
*cc
指向
int
long
时,从
cc
指向的位置只需要一个
char
(一个字节)

分配给
i
,15的值为一个字节。并且,在C实现中,
int
的字节首先与低值字节一起存储,因此,当
cc
指向
i
的第一个字节时,它指向包含15个字节的字节。(一些C实现以不同的顺序存储字节;
cc
可以指向高值字节而不是低值字节。)

分配给
k
,9999的值不适合一个字节。它需要两个字节,低字节为0xf(15),高字节为0x27(39)(因为9999=39*256+15)

因此,第三个
printf
中的
*cc
的值是15。然而,还有另一个问题。由于
cc
是指向
char
的指针,
*cc
char
。在
printf
使用的变量参数列表中,
char
值自动提升为
int
。但是,说明符
%ld
告诉
printf
需要
长int
。你传递了错误类型的论点

当您传递错误类型的参数时,行为不由C规范定义。你不应该指望这会奏效

此外,
%u
是用于打印指针的错误说明符。正确的说明符是
%p
,指针应转换为
void*
。如果将第三个
printf
更改为:

printf("%d, %p", *cc, (void *) cc);
如果要使用
cc
显示
k
的完整值,则必须将
cc
转换为指向
long int
的指针,并使用正确的说明符:

printf("%ld, %p", * (long int *) cc, (void *) cc);

请注意,
cc
只能以这些方式使用,因为C专门处理指向
char
的指针。其他指针类型之间的转换,例如指向
int
的指针和指向
float
的指针,不能保证以这种方式工作。

赋值
cc=&i
cc=&k可能是不允许的,因为它们违反了(C99 6.5.16.1p1)的以下规则[http://www.iso-9899.info/n1256.html#6.5.16.1p1]:

两个操作数都是指向兼容类型的限定或非限定版本的指针, 并且左边指向的类型具有左边指向的类型的所有限定符 对,

在大多数情况下,
char
既不兼容
int
也不兼容
long

编译器应该对此发出警告(确保已启用警告)

在上一个
printf
中,您还传递了一个错误类型的参数,即
int
(由于默认参数提升),而不是
%ld
所需的
long


GCC和clang(可能还有其他人)也会对此发出警告。

您应该刷新最后一个printf.cc的类型是指向char的指针,因此*cc的类型是char