c语言源码解释,C语言一些细节注意(源码+解释)

本文是一篇关于C语言基础知识的分享,涵盖了宏定义如SQR和TSqr的使用,静态变量、数组传递、负数整除取余、指针与内存管理等内容。通过示例代码详细解释了如何进行内存分配、释放以及避免野指针问题,并探讨了结构体内存分配与释放。此外,还讨论了指针、数组和静态变量在不同情况下的sizeof运算结果及其差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近可能要回归底层开发设计,所以又看了看C的一些东西。顺便对一些问题进行了代码确认。现将代码贴出,希望对各位网友有所帮助。

/******************************************************************************

*                                                                            **

*只是为了测试,没有按照什么规范写。代码风格比较烂。哈哈哈哈,大家见谅了。^O^ **

*                                                                            **

*******************************************************************************/

#include #include #include

#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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值