C语言一些细节注意(源码+解释)
时间:2010-03-11 来源:dzt_tomdu
最近可能要回归底层开发设计,所以又看了看C的一些东西。顺便对一些问题进行了代码确认。现将代码贴出,希望对各位网友有所帮助。
/******************************************************************************
* **
*只是为了测试,没有按照什么规范写。代码风格比较烂。哈哈哈哈,大家见谅了。^O^ **
* **
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #define SQR(x) ((x) * (x)) //注意此处一定要把x括起来,避免传入的值有括号或者计算
#define TSqr(x) printf("The square of "#x" is %d\n",((x) * (x))) #define __V 1.0.0 static int j;
/*
fun1 fun2是测试static修饰符的作用的。
*/
int fun1()
{
static int i = 0;
i++;
printf("i=%d ",i);
} int fun2()
{
j = 0;
j++;
printf("j=%d ",j);
}
/*
fun3测试数组的传递。数组传递的是一个地址而不是数组的值。
而且传递的是实参的一个拷贝,而不是实参本身
*/
int fun3(char a[],int b[])
{
printf("\nInput parameter(a) size is %d",sizeof(a)); //所以此处的值在32位机器上是4
printf("\nInput parameter(b) size is %d",sizeof(b)); //所以此处的值在32位机器上是4 printf("\nInput parameter(a[2]) value is %c",a[2]);
printf("\nInput parameter(b[2]) value is %d",b[2]); //数组的第3个元素的值
return;
} /*
fun4 测试负数整除及取余的操作。
测试C语言的几个全局宏定义,这三个宏定义对于写日志文件(log)很有用处
*/
int fun4()
{
printf("A==%d B==%d",(-3)/2,(-3)%2); //这个地方都是-1
printf("\nFile:%s ",__FILE__);
printf("\nLine:%d ",__LINE__);
printf("\nDate:%s ",(char*)__DATE__);
}
/*
* fun5测试数组的相关注意事项,及数组参数传递
*/
int fun5()
{
int a[3][2] = {(0,1),(2,3),(4,5)};
int b[3][2] = {{0,1},{2,3},{4,5}};
int c[5] = {0,1,2,3,4};
char d[5] = "abcde";
int *p;
int *t;
p=a[0];
t=b[0];
printf("\nFalse:%d\n True:%d",p[0],t[0]); //p[0]为1,因为初始化数组是用的是小括号。t[0]是0因为用的是花括号。
printf("\n");
fun3(d,c); //传递地址,数组c的一个拷贝
}
/*
* 测试结构体内部指针内存分配
*/
int fun6()
{
struct sctTest
{
char *name;
int nSex;
};
//定义一个结构体指针
struct sctTest *pTst;
struct sctTest Tst;
//将结构体变量值初始化为0,不过我通过单步调试发现不初始化,结构体内部变量的值也是0,
//但是好的书写规范建议对变量还是进行初始化的好。因为局部变量的值不初始化其值是不定的。
memset(&pTst,0,sizeof(struct sctTest));
memset(&Tst,0,sizeof(struct sctTest));
//初始化结构体指针,分配内存.如果不要这句程序会报错。内存溢出。因为pTst是指针,指针没有合法
//的内存地址指向,导致野指针存在
pTst = (struct sctTest*)malloc(sizeof(struct sctTest));
//初始化结构体中指针name。如果不要这句程序会报错。内存溢出。因为name指针没有合法
//的内存地址指向
if(NULL == pTst)
{
return;
}
pTst->name = (char*)malloc(sizeof(char *));
Tst.name = (char *)malloc(sizeof(char *));
if(NULL == pTst->name || NULL == Tst.name)
{
return;
}
strcpy(pTst->name,"BeiJing");
strcpy(Tst.name,"chiping");
printf("The name of pTst is %s\n",pTst->name);
printf("The name of Tst is %s\n",Tst.name);
//释放,避免野指针出现,避免内存泄露
free(pTst);
free(pTst->name);
free(Tst.name);
pTst=NULL;
return 0;
}
/*
* fun7 测试为什么要在释放内存后将指针指向NULL(哈哈哈,栓野狗的桩子^_^)
*/
int fun7()
{
printf("\nFun7 start\n");
char *pChr = (char *)malloc(sizeof(char *));
if(NULL == pChr)
{
return -1;
}
strcpy(pChr,"abcdefg");
printf("\nString is %s\n &%x",pChr,&pChr);
free(pChr);
//如果不讲pChr指针指向NULL,pChr依然保存上次申请地址时的地址信息。free只是将pChr指针不再指向
//申请的内存地址,不再拥有该内存地址的使用权,但是内容却没有改变,所以要指向NULL
//pChr=NULL;
//char *tt = (char *)malloc(10);
//printf("\ntt address is %x\n",&tt);
/*如果不指向NULL,那么下边这段代码是要出问题的。因为pChr此时不是NULL,但是他没有
*可用的内存了,可用内存被free掉了。所以strcpy时会内存溢出(^_^出问题了,我在gcc环境下
*free掉后下边的代码照常执行,高手看看啥原因呀?这个地方如果是复杂程序有可能会失败。此处的pChr
*已经是野指针了,因为free已经告诉操作系统这块地址pChr不用了,你可以用作其他用途,但是你还用
*那么就是在操作野指针,有时可能不会出错,但是程序不知道什么时候就出错了。这种错误是相当危险了,出现问题后
*你会很难定位问题出现的原因。比如,在调用fun7的时候你循环调用10000次,你就会发现你的程序会在某次
*循环后出错。)
*/
if(NULL != pChr)
{
strcpy(pChr,"aaaaaaaaaaaaaa");
printf("\nString2 is %s\n &%x",pChr,&pChr);
}
return 0;
}
int main()
{
int k = 0;
//以下for循环测试static修饰符
for(k = 0; k < 10; k++)
{
fun1();
fun2(); }
printf("\n");
//测试不同情况下sizeof,切忌sizeof是保留字而不是函数。
printf("sizeof->(int):%d (k):%d k:%d",sizeof(int),sizeof(k),sizeof k); int *p;
//测试指针变量的大小,指针变量的大小是指针存储数据类型的大小
printf("\nint(p) size is %d",sizeof(p));
char *chrP=NULL;
printf("\nchar(p) size is %d",sizeof(chrP)); chrP = (char *)malloc(10*sizeof(char *));
//对指针一定要做判空操作,因为内存申请有可能申请失败
if(NULL != chrP)
{
strcpy(chrP,"abc");
}
printf("\nchar(Assignment p) size is %d",sizeof(chrP));
printf("\nchar(Assignment p) length is %d",strlen(chrP));
void *vP=NULL;
printf("\nvoid(p) size is %d",sizeof(vP));
free(chrP);
free(vP);
chrP = NULL;
vP = NULL;
//通过以上测试确定指针类型的sizeof的值为4。strlen则是指针
//实际指向的地址空间存储的数据的长度(不包括结束符)
//#ifdef __V
#pragma message("__V is defined");
//#endif int a[4];
memset(a,0,sizeof(a));
/*测试数组的首地址及首元素的首地址
*a是整个数组的首元素的首地址,&a是整个数组的首地址
*注意&a+1,这里的1是4*sizeof(int)
*对指针进行加1 操作,得到的是下一个元素的地址,而不是原有地址值直接加1。所以,
*一个类型为T的指针的移动,以sizeof(T) 为移动单位。
*/
printf("\n&a size=%d &a[0] size=%d ",sizeof(&a),sizeof(&a[0]));
printf("\n&a=%d &a[0]%d a=%d &a+1=%d",&a,&a[0],a,&a+1); //int iRef = fun3(a); //测试有符号与无符号数据的计算
int i = -20;
unsigned int j = 10;
printf("\nint + unsigned = %d ",i+j); //测试标识符(//)
char *chrContext="aaaaaaa //bbbbbbbbbbb";
printf("\n// in string :%s",chrContext);
printf("\n"); //测试标识符(#)
TSqr(10);
//测试标识符(##)没有搞定,待高手解决
//XNAME(8);
fun4(); printf("\n"); //测试宏定义注意事项
printf("SQR: %d\n",SQR(10));
fun5();
printf("\n");
fun6();
int tt=0;
//for(tt=0;tt<10000;tt++)
//{
// printf("\ncount=%d\n",tt);
fun7();
//}
return 0;
}
* **
*只是为了测试,没有按照什么规范写。代码风格比较烂。哈哈哈哈,大家见谅了。^O^ **
* **
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #define SQR(x) ((x) * (x)) //注意此处一定要把x括起来,避免传入的值有括号或者计算
#define TSqr(x) printf("The square of "#x" is %d\n",((x) * (x))) #define __V 1.0.0 static int j;
/*
fun1 fun2是测试static修饰符的作用的。
*/
int fun1()
{
static int i = 0;
i++;
printf("i=%d ",i);
} int fun2()
{
j = 0;
j++;
printf("j=%d ",j);
}
/*
fun3测试数组的传递。数组传递的是一个地址而不是数组的值。
而且传递的是实参的一个拷贝,而不是实参本身
*/
int fun3(char a[],int b[])
{
printf("\nInput parameter(a) size is %d",sizeof(a)); //所以此处的值在32位机器上是4
printf("\nInput parameter(b) size is %d",sizeof(b)); //所以此处的值在32位机器上是4 printf("\nInput parameter(a[2]) value is %c",a[2]);
printf("\nInput parameter(b[2]) value is %d",b[2]); //数组的第3个元素的值
return;
} /*
fun4 测试负数整除及取余的操作。
测试C语言的几个全局宏定义,这三个宏定义对于写日志文件(log)很有用处
*/
int fun4()
{
printf("A==%d B==%d",(-3)/2,(-3)%2); //这个地方都是-1
printf("\nFile:%s ",__FILE__);
printf("\nLine:%d ",__LINE__);
printf("\nDate:%s ",(char*)__DATE__);
}
/*
* fun5测试数组的相关注意事项,及数组参数传递
*/
int fun5()
{
int a[3][2] = {(0,1),(2,3),(4,5)};
int b[3][2] = {{0,1},{2,3},{4,5}};
int c[5] = {0,1,2,3,4};
char d[5] = "abcde";
int *p;
int *t;
p=a[0];
t=b[0];
printf("\nFalse:%d\n True:%d",p[0],t[0]); //p[0]为1,因为初始化数组是用的是小括号。t[0]是0因为用的是花括号。
printf("\n");
fun3(d,c); //传递地址,数组c的一个拷贝
}
/*
* 测试结构体内部指针内存分配
*/
int fun6()
{
struct sctTest
{
char *name;
int nSex;
};
//定义一个结构体指针
struct sctTest *pTst;
struct sctTest Tst;
//将结构体变量值初始化为0,不过我通过单步调试发现不初始化,结构体内部变量的值也是0,
//但是好的书写规范建议对变量还是进行初始化的好。因为局部变量的值不初始化其值是不定的。
memset(&pTst,0,sizeof(struct sctTest));
memset(&Tst,0,sizeof(struct sctTest));
//初始化结构体指针,分配内存.如果不要这句程序会报错。内存溢出。因为pTst是指针,指针没有合法
//的内存地址指向,导致野指针存在
pTst = (struct sctTest*)malloc(sizeof(struct sctTest));
//初始化结构体中指针name。如果不要这句程序会报错。内存溢出。因为name指针没有合法
//的内存地址指向
if(NULL == pTst)
{
return;
}
pTst->name = (char*)malloc(sizeof(char *));
Tst.name = (char *)malloc(sizeof(char *));
if(NULL == pTst->name || NULL == Tst.name)
{
return;
}
strcpy(pTst->name,"BeiJing");
strcpy(Tst.name,"chiping");
printf("The name of pTst is %s\n",pTst->name);
printf("The name of Tst is %s\n",Tst.name);
//释放,避免野指针出现,避免内存泄露
free(pTst);
free(pTst->name);
free(Tst.name);
pTst=NULL;
return 0;
}
/*
* fun7 测试为什么要在释放内存后将指针指向NULL(哈哈哈,栓野狗的桩子^_^)
*/
int fun7()
{
printf("\nFun7 start\n");
char *pChr = (char *)malloc(sizeof(char *));
if(NULL == pChr)
{
return -1;
}
strcpy(pChr,"abcdefg");
printf("\nString is %s\n &%x",pChr,&pChr);
free(pChr);
//如果不讲pChr指针指向NULL,pChr依然保存上次申请地址时的地址信息。free只是将pChr指针不再指向
//申请的内存地址,不再拥有该内存地址的使用权,但是内容却没有改变,所以要指向NULL
//pChr=NULL;
//char *tt = (char *)malloc(10);
//printf("\ntt address is %x\n",&tt);
/*如果不指向NULL,那么下边这段代码是要出问题的。因为pChr此时不是NULL,但是他没有
*可用的内存了,可用内存被free掉了。所以strcpy时会内存溢出(^_^出问题了,我在gcc环境下
*free掉后下边的代码照常执行,高手看看啥原因呀?这个地方如果是复杂程序有可能会失败。此处的pChr
*已经是野指针了,因为free已经告诉操作系统这块地址pChr不用了,你可以用作其他用途,但是你还用
*那么就是在操作野指针,有时可能不会出错,但是程序不知道什么时候就出错了。这种错误是相当危险了,出现问题后
*你会很难定位问题出现的原因。比如,在调用fun7的时候你循环调用10000次,你就会发现你的程序会在某次
*循环后出错。)
*/
if(NULL != pChr)
{
strcpy(pChr,"aaaaaaaaaaaaaa");
printf("\nString2 is %s\n &%x",pChr,&pChr);
}
return 0;
}
int main()
{
int k = 0;
//以下for循环测试static修饰符
for(k = 0; k < 10; k++)
{
fun1();
fun2(); }
printf("\n");
//测试不同情况下sizeof,切忌sizeof是保留字而不是函数。
printf("sizeof->(int):%d (k):%d k:%d",sizeof(int),sizeof(k),sizeof k); int *p;
//测试指针变量的大小,指针变量的大小是指针存储数据类型的大小
printf("\nint(p) size is %d",sizeof(p));
char *chrP=NULL;
printf("\nchar(p) size is %d",sizeof(chrP)); chrP = (char *)malloc(10*sizeof(char *));
//对指针一定要做判空操作,因为内存申请有可能申请失败
if(NULL != chrP)
{
strcpy(chrP,"abc");
}
printf("\nchar(Assignment p) size is %d",sizeof(chrP));
printf("\nchar(Assignment p) length is %d",strlen(chrP));
void *vP=NULL;
printf("\nvoid(p) size is %d",sizeof(vP));
free(chrP);
free(vP);
chrP = NULL;
vP = NULL;
//通过以上测试确定指针类型的sizeof的值为4。strlen则是指针
//实际指向的地址空间存储的数据的长度(不包括结束符)
//#ifdef __V
#pragma message("__V is defined");
//#endif int a[4];
memset(a,0,sizeof(a));
/*测试数组的首地址及首元素的首地址
*a是整个数组的首元素的首地址,&a是整个数组的首地址
*注意&a+1,这里的1是4*sizeof(int)
*对指针进行加1 操作,得到的是下一个元素的地址,而不是原有地址值直接加1。所以,
*一个类型为T的指针的移动,以sizeof(T) 为移动单位。
*/
printf("\n&a size=%d &a[0] size=%d ",sizeof(&a),sizeof(&a[0]));
printf("\n&a=%d &a[0]%d a=%d &a+1=%d",&a,&a[0],a,&a+1); //int iRef = fun3(a); //测试有符号与无符号数据的计算
int i = -20;
unsigned int j = 10;
printf("\nint + unsigned = %d ",i+j); //测试标识符(//)
char *chrContext="aaaaaaa //bbbbbbbbbbb";
printf("\n// in string :%s",chrContext);
printf("\n"); //测试标识符(#)
TSqr(10);
//测试标识符(##)没有搞定,待高手解决
//XNAME(8);
fun4(); printf("\n"); //测试宏定义注意事项
printf("SQR: %d\n",SQR(10));
fun5();
printf("\n");
fun6();
int tt=0;
//for(tt=0;tt<10000;tt++)
//{
// printf("\ncount=%d\n",tt);
fun7();
//}
return 0;
}
相关阅读 更多 +