前段时间听了CSDN在线讲堂的嵌入式C学习关于指针的课,下面是我的学习笔记,记下了我认为比较重要的知识点,笔记并不全面,就算是学习的tips。
#define INT_T int* typedef int* int_t; void main(){ INT_T p1,p2; int_t q1,q2; }
这两种定义方式是有区别的。
第一种的情况是,在编译之前,编译器用int*替代代码中的INT_T,所以INT_T p1,p2;相当于int* p1,p2;所以p1为指向int型的指针,p2为int型变量。
第二种情况,typedef将int*定义为一种类型,叫int_t,所以q1、q2都为指向int型的指针。
引深:
在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。
typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱。
所有自定义的类型(如用typedef定义的类型)的名字加_t后缀,便于程序阅读。
int main(){ int **p; int a; *p=&a; return 0; }
这段代码编译能够通过,但会引发段错误。原因在于,**p指向了未知的内存空间,造成了段错误。**p为二级指针,它存储指针*p的地址,*p指向int型变量a。但此处*p并没有声明或定义,所以是未知的、不可访问的内存空间,而**p指向了它,造成了段错误。
指针必须指向可访问、已知的内存空间。
上面的代码改成下面的就正确了:
int main(){ int **p; int *q; int a; q=&a; p=&q; return 0; }
在实际的编程中一定要注意这样的问题,确保指针指向可访问、已知的内存空间,否则会造成不易察觉的错误。
引深:
C语言中函数调用机制决定了直接改变参数的值对调用者无效。因为调用函数会开辟新的空间,在调用函数内声明定义的变量仅在此函数内有效,当函数调用结束时编译器自动释放了这段空间。而此函数的形参仅仅是调用者传递的实参的副本,对副本值的改变不会影响到调用者中实参的值。在C语言中,参数相当于局部变量。如果使用指针传递,则调用函数中的形参是要改变值的对象的地址的副本,对此副本指向空间的内容的改变将影响到调用者中对象的值。C++中的引用是指向变量的别名,注意其与指针的区别。
int *func(void){ int b=200; return &b; }
此代码片段是错误的。根据上面说的函数的调用机制,变量b为局部变量,其内存空间在函数调用完之后便被编译器释放了,所以返回的地址指向了未知、不可访问的内存空间,造成段错误。
引深:
函数可以返回全局变量指针、静态变量指针、malloc分配的内存块的指针,不可以返回局部变量的指针。
void main(){ int *p; char *q; p++; //向后移动4个字节 q++; //向后移动1个字节 }
指针变量累增,累增的字节数为其所指向对象占用空间的大小。
struct Test *sp; sp++; //向后移sizeof(struct Test)个字节
int main(){ int a=0x12345678; printf("%x/n",*((char *)&a)); //显示结果为:78 printf("%x/n",*((short *)&a)); //显示结果为:5678 printf("%x/n",*((int *)&a)); //显示结果为:12345678 }
啊,ubuntu下的画图软件openoffice.org图画不能保存为jpg文件,只好自己说了。在内存空间中,a占用4字节,char为1字节,short为2字节。在第一个输出中,将&a强制转换为指向char类型的指针,所以只显示&a指向地址后1字节中的内容,即78.同理,第二个输出为5678。第三个自然是12345678.此例说明了指针必须指定其指向变量类型的意义。
int test_endian(void){ int a=0x12345678; return *((char *)&a)==0x78; }
返回值中使用了逻辑表达式,非常的简洁。
希望上述的笔记对大家有帮助。