今天有点时间看看c和指针的第六章,真的是闲的没有事情干。。。
读完这一章我感觉稍微有点感想吧,由于以前用过很多次指针,所以书本上的知识都知道,所以我想在这里简单的总结一下,方便以后复习。。
首先我想提出一个问题:
1.如果把一个float类型的变量的地址复制给int类型的指针,无论使用不使用强制类型转化,之后再把int指针的值输出,请问会输出什么。
#include <stdio.h>
int main (void) {
float a = 3.14;
int *p = &a;
printf("%d\n",p);
return 0;
}
答案 :输出变成一个很大的数字。
为什么呢 ?
这是浮点数存储和int类型的存储不一样的问题。但是这不是我要说的问题,如果有人喜欢请看IEEE 754标准
我在提出一个问题:
2.如果把一个float类型的变量直接使用%d打印出来,不使用强制类型转换,会输出什么呢?
#include <stdio.h>
int main (void) {
float a = 3.14;
printf("a = %d\n",a);
return 0;
}
为什么呢?
这也是浮点数和int类型存储不一样导致的,但是重点来了,如果上面两个代码打出之后你会发现打印的数字不一样,为什么呢,引出了我第三个问题:
3.为什么一个float类型的变量给int类型指针使用%d打印出来的数字和float类型变量直接使用%d打印出来的数字不一样呢,同样的地址,同样的%d,为什么呢?
在这里我想说我也是花了一晚上的时间通过测试代码才想出来的,首先我们要知道如果打印乎float变量的二进制,不是float的地址啊,请注意,是float变量的二进制。
#include <stdio.h>
int main (void) {
float a = 1;
int i,s = 1;
unsigned int *temp = (unsigned int* ) &a;
for (i = 31;i >= 0;i--) {
if((s<<i)&(*temp))
printf("1");
else
printf("0");
if(i == 31 || i == 31-8 )
printf(" ");
}
printf("\n");
return 0;
}
这个就能打印出a(float)变量的二进制。由于我使用了float 4个字节,使用unsigned int* 就可以保存下去,如果使用int* 也可以完整的保存float二进制。在这里我不想多说。
接着我猜想到。
#include <stdio.h>
int main (void) {
int i,s = 1;
float a = 3.14;
int *p = (int*) &a;
unsigned int *pu = (unsigned int*) &a;
printf("使用的int指针\n");
for (i = 31;i >= 0;i--) {
if ((s<<i) & (*p))
printf("1");
else
printf("0");
if (i == 31 || i == 31-8) printf(" ");
i == 0 && printf("\n");
}
printf("p = %d\n",*p);
printf("使用的unsigned指针\n");
for (i = 31;i >= 0;i--) {
if ((s<<i) & (*pu))
printf("1");
else
printf("0");
if (i == 31 || i == 31-8) printf(" ");
i == 0 && printf("\n");
}
printf("pu = %u\n",*pu);
printf("a = %d\n",a);
printf("sizeof(float) = %d\n",sizeof(a));
printf("sizeof(int) = %d\n",sizeof(int));
return 0;
}
我分别使用int 和 unsigned int两种类型打印出float a 变量的二进制,发现都是一样的,但是只要是使用a直接打印就发现和他们表示的数字是不一样的,我突然想到,如果一个float类型+一个int类型会经过隐式类型的转换,之后我写出代码。
#include <stdio.h>
int main (void) {
double a = 1;
printf("sizeof(long long) = %d\n",sizeof(long long));
printf("sizeof(double) = %d\n",sizeof(double));
printf("sizeof(unsigned long long) = %d\n",sizeof(unsigned long long));
long long *p = (long long *) &a;
unsigned long long *pu = (unsigned long long *) &a;
int i,s = 1;
for (i = 63;i >= 0;i --) {
if ((s<<i) & (*p))
printf("1");
else
printf("0");
if (i == 63 || i == 63-11) printf(" ");
i == 0 && printf("\n");
}
for (i = 63;i >= 0;i--) {
if ((s<<i) & (*pu))
printf("1");
else
printf("0");
if (i == 63 || i == 63-11) printf(" ");
i == 0 && printf("\n");
}
printf("p = %lld\n",*p);
printf("pu = %llu\n",*pu);
printf("a = %lld\n",a);
return 0;
}
发现和我想到的一样,最后我得到答案就是 在使用a变量直接%d打印的时候a变量由于是float类型他如果要int类型打印的话,需要进行隐式类型的转换,所以他会先转换成double类型,之后再进行打印,由于double类型是8个字节,int类型只能打印出其后4个字节的内容,但是如果使用了把float变量的地址给int类型的指针的时候就不会出现这个问题,他们会把float类型的地址直接打印出来,不会有舍弃的位数。
虽然能这样说,但是你直接使用一个指向float变量的int指针之后给他做移31,之后%d打印出来和float变量%d打印出来的数字还是有些区别的,我想是由于float在转化成double类型的时候还是有一些区别的。
这写问题只是我突然看到这c和指针第六章突然想到的,我还没有说完,还有问题:
4.操作符的使用次数问题。
给你一段代码你判断一下会输出什么。
#include <stdio.h>
int main (void) {
char c = 'a';
char *pc = &c;
printf("pc = %c\n",++*pc++);
return 0;
}
你要是看到这个代码如果不打印代码的话,你能说出来他会输出什么么,我一开始看到这个时候我有点蒙了,后来要是通过代码测试想到的。
随便说一下,在printf结束后pc的指向和c变量内容的变化。
在这里我想说明的是操作符的分类性(这个名词好像不太明白,这个我也是想出来的,我不知道应该如何说才会具体一点,毕竟从小到大语文都不及格的。)
最后printf输出 ‘b'
pc会指向c变量地址的后一个地址。相当于c变量地址自加。
在这里我是这样想的,高优先级的在一起执行,低优先级的在一起执行。
如果是这个代码你会怎么想:
#include <stdio.h>
int main (void) {
char c = 'a';
char *pc = &c;
printf("pc = %c\n",++(*pc)++);
return 0;
}
这个输出就有一点不一样了。你能想象输出么。
结果是编译错误,有没有想到啊,反正我是没有想到。
这个出现的错误一般就是
lvalue required as increment operand
意思就是 右值不能前置
也叫ub = “未定义行为”
这个出现的问题在于
前++ 不能给左值进行自加行为导致的。