一,程序找错
1,
char *getmem()
{
char p[]="hello world";
return p;
}
int main()
{
char *str=NULL;
str=getmem();
printf("%s\n",str);
}
以上程序出错的原因是getmem函数里p是一个本地变量,是在栈上申请内存的,返回时候就释放了,正确的应该是调用malloc函数从堆上申请,返回时候不会释放,在main()函数里程序员主动释放。
正确的如下:
char *getmem()
{
char *p=(char*)malloc(20);
strcpy(p,"hello world");
return p;
}
int main()
{
char *str=NULL;
str=getmem();
printf("%s\n",str);
free(str);
return 0;
}
2,
void getmem(char *p)
{
p=(char*)malloc(100);
p="hello world";
}
int main()
{
char *str=NULL;
getmem(str);
printf("%s\n",str);
}
以上程序出错的原因是getmem函数里,p用malloc分配了一块内存,然后又将内存指向 了常量区域,这样malloc()分配的内存永远不能得到释放,这样会造成内存泄露,另外主函数里的调用getmem(str),在返回的时候str仍然指向空,形参和实参的差别。因为要要改变指针的值,所以要将指针本身的地址当作函数参数传进去。要改变函数参数的值,就要将该值的地址传进去。
正确的应该如下:
void getmem(char **p)
{
*p=(char*)malloc(100);
strcpy(*p,"hello world");
}
int main()
{
char *str=NULL;
getmem(&str);
printf("%s\n",str);
free(str);
return 0;
}
void swap(int *a, int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
} //标准的交换两个数的函数
3,正确处理C语言的整型溢出的问题
对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”,也就是说,如果一个unsigned char(1字符,8bits)溢出了,会把溢出的值与256求模。例如:
1,unsigned char x = 0xff;
2,printf("%d\n", ++x);
上面的代码会输出:0 (因为0xff + 1是256,与2^8求模后就是0)
对于signed整型的溢出,C的规范定义是“undefined behavior”,也就是说,编译器爱怎么实现就怎么实现。对于大多数编译器来说,算得啥就是啥。比如:
signed char x =0x7f; //注:0xff就是-1了,因为最高位是1也就是负数了
printf("%d\n", ++x);
上面的代码会输出:-128,因为0x7f + 0×01得到0×80,也就是二进制的1000 0000,符号位为1,负数,后面为全0,就是负的最小数,即-128。
4,C语言类型在32位和64位机器上的长度
char | short | int | long | ptr | long-long | ||
32位 | 1 | 2 | 4 | 4 | 4 | 8 | |
62位 | 1 | 2 | 4 | 8 | 8 | 8 |
5,int long对应的最大值
int ->32位,最高位是正负位所以实际值只有31位,那它的最大值=2^31-1 = 2147483647.
unsigned int ->2^32 -1 = 4294967295
long long ->2^63 -1 = 92233720368547758007
unsigned long long ->2^64-1=18446744073709551615
6,内存对齐
#pragma pack(1)
struct node{
char f;
int e;
short int a;
char b;};
struct node n;
printf("%d\n",sizeof(n));
这里强制按照1字节进行对齐,可以理解成所有的内容都是按照1字节进行读取(暂且这样理解,因为这样可以很好的理解内存对其机制),
其他所有的数据成员都是1字节的整数倍,所以也就不用进行内存对其,各个成员在内存中就按照实际顺序进行排列,结构体实际长度为8
#pragma pack(2)
struct node{
char f;
int e;
short int a;
char b;};
struct node n;
printf("%d\n",sizeof(n));
这里强制按照2字节进行对齐。如果内存分布仍然是连续的话,那么int e就得三次才能读到CPU中,所以为了“讲究”int e的读取,
所以在char f之后预留1BYTE,最后的char b也是如此,所以长度为10
#pragma pack(4)
struct node{
char f;
int e;
short int a;
char b;};
struct node n;
printf("%d\n",sizeof(n));
这里强制按照4字节进行对齐。所以char f后要预留3BYTE,而short int a 和 char b可以一次读取到CPU(按照4字节读取),所以长度为12
如果#pramga pack(n)中的n大于结构体成员中任何一个成员所占用的字节数,则该n值无效。编译器会选取结构体中最大数据成员的字节数为基准进行对其
7,内联函数和宏定义的区别
内联函数在编译的时候内联函数可以直接呗镶嵌到目标代码中,宏不是函数,只是在编译前(编译预处理阶段)将程序中有关字符串替换成宏体,宏是在代码处不加任何验证的简单替代,而内联函数是将代码直接插入调用处,而减少了普通函数调用时的资源消耗,宏是在代码处不加任何验证的简单替代,而内联函数是将代码直接插入调用处,而减少了普通函数调用时的资源消耗, inline 可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。