C语言基础

1.int, float, double这三种类型是不兼容的。
2.int, short, char这三种类型兼容。相互转换的时候可能错也可能对。如char 和int之间的转换,当数值是在char所表示的范围之内的时候就不会出错,但是若是超过了char的范围后就会出错。
3.所有指针类型(int *, double *, char *,,,)的解析方式都是相同的,都是将所占的4个字节的32个二进制加起来所代表的内存地址。指向不容类型的指针是相互兼容的,但是指针指向的变量就不一定兼容了。
4.char *a = "linux"; //那么a指向的字符串是分配在代码段的,这是不可修改的。




5.指针
指针的本质是变量,指针就是指针变量。
一个指针涉及两个变量,一个是指针变量自己本身,一个是指针指向的那个变量。int *p;定义指针变量时,p(指针变量本身)是int * 类型,而*p(指向的那个变量)是int类型。


int *类型说白了就是指针类型,只要是指针类型就都是占4个字节(貌似我的PC机中的占8个字节),解析方式都是按照地址的方式来解析(4个字节里的32个二进制加起来表示一个内存地址)的。所以所有的指针类型(int *, char *, double *...)的解析方式是相同的,都是地址。
对于指针所指向的那个变量来说,指针的类型就很重要了,指针所指向的那个变量的类型(它所对应的内存空间的解析方法)要取决于指针类型。如果指针是int *类型,那么指针所指向的变量就是int类型的。


6.sizeof是C语言的一个运算符,注意sizeof并不是函数,sizeof()的作用是用来返回()里面的变量或者数据类型占用的内存字节数。不同平台下各种数据类型所占的内存字节数不尽相同,所以程序中需要用sizeof来判断当前变量、数据类型在当前环境下占几个字节。
sizeof(数组名)中返回的是整个数组所占用的内存空间(以字节为单位)。
7.函数形参是数组时,实际传递的不是整个数组,而是数组的首元素首地址,也就是说函数传参用数组来传,相当于传递的是指针。
8.普通变量作为参数时,形参和实参的名字可以相同也可以不同,形参申请一个新的空间从实参那里拷贝一份存放着。形参和实参是独立存在的。这就是所谓的“传值调用”。
9.当数组名作为函数形参时,实际上传递的不是整个数组,而是数组的首元素的首地址(也是整个数组的首地址。)
在子函数内传参得到的数组首元素首地址,和外面得到的数组首元素首地址的地址值是相同的,这就是所谓的“传址调用”,于是子函数内就可以通过地址来进行访问实参。这时候只有一份变量,而不像传值那样有两份一样的变量。
10.指针作为形参和数组名作为形参一样。
11.结构体变量作为函数形参和普通变量一样,都是自己申请一段内存从实参那边拷贝过来,但是当结构体比较大的时候,如果还是直接用结构体变量进行传参,那么函数调用效率就会大大降低,所以我们就不直接传变量,而是传变量的指针(地址)进去。
12.数组传参的时候传递的是首元素首地址,这是C语言编译器强制规定了,但是传结构体的时候,编译器让我们编程者自己来选择到底是传指针还是传变量。


13.实际上实参是永远都无法被传进子函数中的,要么是被拷贝一份,要么是传实参的地址进去,然后通过指针的解引用从子函数内部访问到外部的x和y真身,从而改变x和y。


14.函数名是一个符号,表示整个函数代码段的首地址,实际上是一个指针常量,所以在程序中使用到函数名时都是当地址用的,用来调用这个函数。
15.我们可以把函数当做一个加工机器,形参(输入)就是加工的原材料,返回值(输出)就是加工后的成品。
16.程序中也可以通过全局变量来对数据进行加工,但是在实践中更多的是使用函数传参,因为这样可以实现模块化编程,而C语言中也是尽量减少使用全局变量的。
17.全局变量传参最大的好处就是省略了函数传参的开销,所以效率会高一些,然而实践中还是通过传参,如果参数很多就将这些参数打包成一个结构体,然后传结构体变量指针进子函数中。


18.现实编程中,一个函数需要返回多个值是通过参数来做返回(Linux风格函数中,返回值不用来返回结果,而是返回0或者-1来表示程序执行结果的对错)。如果这个参数是用来做输入的,就叫输入型参数,如果这个参数是用来做输出的,就叫输出型参数。输出型参数就是用来让函数内部把数据输出到函数外部的。


19.函数传参时如果传的是普通变量,那么肯定是输入型参数,如果穿的是指针,可能是输入也可能是输出。区别的方法就是在输入型参数就在指针前面加上const来修饰而输出型参数不加。


20.指针数组和数组指针
指针数组的实质是一个数组,这个数组中存储的内容是指针变量。
数组指针的实质是一个指针,这个指针指向一个数组。
21.我们在剖析一个符号时,首先要搞清楚定义的符号是谁(找核心),然后再看谁跟核心结合(找结合),继续向外扩展(继续向外结合直至整个符号结束)。
如果核心和*结合,表示核心是指针,如果核心和[]结合,表示核心是数组,如果核心和()结合,表示核心是函数。
22.int *p[5]; int (*p)[5]; int * (p[5]);
int *p[5]:[]的优先级比*的高,所以p[5]是一个数组,然后这个数组存放的都是指针,指针指向的元素类型是int;所以int *p[5]就是一个指针数组。
int (*p)[5]:首先p是一个指针,然后这个指针指向一个数组,数组中存放的是int类型元素,所以int (*p)[]就是一个数组指针。
int * (p[5]):和int *p[5]一样。
找到核心后从内到外逐层的进行结合,结合之后可以把已经结合的部分看成一个整体,然后再去和整体外边的继续进行结合。


23.函数指针的实质还是指针,还是指针变量,在32位系统中,所有的指针都是占4字节。
函数指针,数组指针,普通指针之间唯一的区别在于指针指向的东西不一样而已。函数指针指向的是函数,数组指针指向的是数组,普通指针指向的是普通的变量。
函数的实质是一段代码,这一段代码在内存中是连续分布的(一个函数的大括号括起来的所有语句将来编译出来生成的可执行程序是连续的),所以对于函数来说很关键的就是函数中的第一句代码的地址,这个地址就是所谓的函数地址,在C语言中用函数名这个符号来表示。
函数指针其实就是一个普通的变量,这个普通变量的类型指向的是函数指针变量类型,这个变量的值就是某个函数的地址。(也就是它的函数名这个符号在编译器中对应的值)。


C语言本身就是一个强类型语言(每一个变量都有自己的变量类型),这样编译器可以帮助我们做严格的类型检查,能够避免很多错误,但是这样就要求我们遵循的规则更多了。
函数:void func(void);->  void (*p)(void);
首先p会和*结合,这样p就是一个指针,然后和()结合,说明这是一个函数指针。


在定义某个函数的函数指针的时候,一定要注意各参数个数、类型和返回值的类型必须得保持一样。char * strcpy(char * dest, const char *src);->  char * (*pFunc)(char * , const char *);


函数名和数组名的最大区别就是:函数名做右值时加不加&效果和意义都一样,但是数组名做右值时不加&表示首元素的首地址,加&的时候表示的是整个数组的首地址。
/*
int *p;
int a[5];
p = a; //类型匹配,无警告。
p = &a; //类型不匹配,有警告。p 是一个int类型的指针,而&a是整个元素的首地址
*/
/*
void func1(void)
{
printf)("I am func1.\n");
}
void (*pFunc)(void);
pFunc = func1; //类型匹配
pFunc = &func1; //类型匹配
pFunc(); //函数指针调用函数。
*/
/*
char a[5] = {0};
char* (*pFunc)(char *, const char *);
pFunc = strcpy; //pFunc指向strcpy函数,函数库中的strcpy。
pFunc(a, "abc"); //通过函数指针调用函数。
printf("a = %s.\n",a);
*/
24.typedef关键字的用法:typedef是一个关键字,作用是用来定义(重命名)类型;
我们都知道C语言中除了编译器定义的原生类型(int ,float, double...)之外还能够自定义类型(如数组类型、结构体类型、函数类型...)
有时候自定义类型太长了,用来定义变量的时候不方便,所以我们就可以用typedef给这个类型重命名一个短一些的名字。
/*
//重命名了一个类型,这个新类型的名字pType,类型是:char * (*) (char *, const char *);
typedef char * (*pType)(char *, const char *);
char a[5] = {0};
pType p1;
p1 = strcpy;
p1(a, "abc");
printf("a = %s.\n", a);
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值