近期一段时间參加一些面试,发现非常多细节的问题自己已经变得非常模糊了。对一些曾经常常遇到的错误。如今也说不出原因了。
而且在编码过程中也相同犯这些错误。
特别写一个博客来记录这些我们常常遇到的错误。自己也在gitHUb上创建了一个库。来总结这些错误。
地址:https://github.com/jinshaohui/C_Error_problem。希望大家有遇到相同问题的都提交到这里。
废话少说。来正题吧,先来说说数据类型使用过程中遇到的问题吧!
看以下的代码会输入什么?为什么 ?
/*File : type_conversion.c
*Auth : sjin
*Date : 20141018
*Mail : 413977243@qq.com
*/
#include <stdio.h>
int array[] = {10,20,30,40};
#define TOTAL_EMEMENTS (sizeof(array)/sizeof(array[0]))
/*另外一个样例
*代码输出什么?为什么?
* */
int fun()
{
unsigned int a = 6;
int b = -20;
(a + b > 6)? puts("a + b > 6"):puts("a + b < 6");
}
int main()
{
int d = -1;
if (d <= TOTAL_EMEMENTS){
printf("##[sjin] : the array total emements is %d
",TOTAL_EMEMENTS);
}else {
printf("##[sjin] : the array is empty!
");
}
fun();
return 0;
}
输入例如以下:
##[sjin] : the array is empty!
a + b > 6
TOTAL_EMEMENTS 所定义的值是unsigned int类型(由于sizeif返回值是无符号的),if语句在unsigned int 和int之间測试相等性 。所以d被升级为unsigend int类型。-1转换为unsigned int类型是一个巨大的整数。致使表达式的值为假。所以在比較前,须要对宏定义前加int类型的强制转换。这个问题就是潜在类型转换导致的。
函数fun()中的错误也相同是这个问题。
在对宏定义中。使用以下语句:
#define TOTAL_EMEMENTS (sizeof(array)/sizeof(array[0]))
而不是:#define TOTAL_EMEMENTS (sizeof(array)/sizeof(int))
非常明显。在代码可扩展性方面。我们在不改变#define语句的情况下能够任意改变数据的基本类型(int变成char).sizeof 是keyword而不是函数,看以下的代码:
/*File : sizeof.c
*Auth : sjin
*Date : 20141018
*Mail : 413977243@qq.com
*/
#include <stdio.h>
/*sizeof 是keyword,不是函数
*计算数据空间的字节数
* */
void fun(char b[100])
{
printf("##[sjin] in fun sizeof(b): %d
",sizeof(b));
}
int main()
{
double *p = NULL;
char a[100] = {' '};
double *(*b)[3][6];
int d = 0;
printf("##[sjin] sizeof(int): %d
",sizeof(int));
printf("##[sjin] sizeof(d): %d
",sizeof(d));
printf("##[sjin] sizeof d: %d
",sizeof d );
//以下编译错误
//printf("##[sjin] sizeof int: %d
",sizeof int );
printf("##[sjin] sizeof(p): %d
",sizeof(p)); //p是一个指针
printf("##[sjin] sizeof(*p): %d
",sizeof(*p));//*p 为一个double的变量
printf("##[sjin] sizeof(a): %d
",sizeof(a));//a是一个数组
printf("##[sjin] sizeof(a[0]): %d
",sizeof(a[0]));//a[0] 是一个char型变量
printf("##[sjin] sizeof(&a): %d
",sizeof(&a));//&a 是a的地址
printf("##[sjin] sizeof(&a[0]): %d
",sizeof(&a[0]));//&a[0] 是a[0]的地址
printf("##[sjin] sizeof(b): %d
",sizeof(b));
printf("##[sjin] sizeof(*b): %d
",sizeof(*b));
printf("##[sjin] sizeof(**b): %d
",sizeof(**b));
printf("##[sjin] sizeof(***b): %d
",sizeof(***b));
printf("##[sjin] sizeof(****b): %d
",sizeof(****b));
fun(a);
}
输入例如以下:
##[sjin] sizeof(int): 4
##[sjin] sizeof(d): 4
##[sjin] sizeof d: 4
##[sjin] sizeof(p): 4
##[sjin] sizeof(*p): 8
##[sjin] sizeof(a): 100
##[sjin] sizeof(a[0]): 1
##[sjin] sizeof(&a): 4
##[sjin] sizeof(&a[0]): 4
##[sjin] sizeof(b): 4
##[sjin] sizeof(*b): 72
##[sjin] sizeof(**b): 24
##[sjin] sizeof(***b): 4
##[sjin] sizeof(****b): 8
##[sjin] in fun sizeof(b): 4
sizeof int 表示什么啊?int 前面加一个keyword?类型扩展?明显不对。我们能够在 int 前加 unsigned,const 等keyword但不能加 sizeof。好,记住:sizeof 在计算 变量所占空间大小时, 括号能够省略.
来说下函数传參,数组作为形參时,当作是一个指针, 所以是一个指针的大小。
double *(*b)[3][6]; 这个比較难理解。
b是一个指向double *[3][6] 类型的指针。所以大小也为4个字节。
*b 是表示一个double*【3】【6】多维数组的类型。而数组元素都是double*类型的指针。所以
sizeof(*b) = 3*6*sizeof(double*) = 72
**b是表示一个 double*【6】的数组,所以sizeof(**b) = 6*sizeof(double*) = 24
***b是表示一个double*的元素指针,所以sizeof(***b) = sizeof(double*) = 4
****b是表示一个double类型的数值。所以sizeof(****b) = sizeof(double) = 8
union 联合体
考虑存储模式:大端模式和小端模式。
大端模式(Big_endian) :字数据的 高字节存储在 低地址中,而字数据的 低字节则存放
在 高地址中。
小端模式(Little_endian) :字数据的 高字节存储在 高地址中,而字数据的 低字节则存放
在 低地址中。
union 型数据所占的空间等于其最大的成员所占的空间。对 union 型的成员的存取都是
相对于该联合体基地址的偏移量为 0 处開始, 也就是联合体的訪问不论对哪个变量的存取都
是从 union 的首地址位置開始。
/*File : union.c *Auth : sjin *Date : 20141022 *Mail : 413977243@qq.com */ #include <stdio.h> /*这里来说明面试中常常问的一个问题 *推断系统的大小端问题 *存储模式:大端模式和小端模式。* 大端模式(Big_endian) :字数据的 高字节存储在 低地址中,而字数据的 低字节 则存放在高地址中。 * 小端模式(Little_endian) :字数据的 高字节存储在 高地址中,而字数据的 低字节则存放在低地址中。
*union 型数据所占的空间等于其最大的成员所占的空间。对 union 型的成员的存取都是 *相对于该联合体基地址的偏移量为 0 处開始, 也就是联合体的訪问不论对哪个变量的存取都 *是从 union 的首地址位置開始. */ /* True: 小端模式 * False:大端模式 */ int checkSystem() { union check{ int i; char ch; }c; c.i = 1; return (c.ch == 1); } int main() { if(checkSystem()){ printf("当前系统为小端模式 "); }else{ printf("当前系统为大端模式 "); } return 0; }