C和指针 阅读笔记(1-5章)

所有的C程序必须有一个main函数,它是程序执行的起点,函数标量通过传值调用,而数组名具有引用传递的语义。C语言(非C++)无字符串类型,默认字符串类型就是以NUL结束的字符;并且有一组函数专门操作字符串:

1 printf       //格式化输出            %d:十进制整型 ,  %g:浮点型,   %c:字符,        %s:字符串
2 scanf       //格式化输入            
:换行
3 getchar   //非格式化输入
4 putchar   //非格式化输出

定义一个长度为5的数组: int  arr[5]

while循环内遇到continue,直接开始下一轮循环;而for循环遇到continue,则直接进入循环内的下一个条件的判断部分,而不是直接进入下一轮循环。共同点:break都会永久退出最内层循环。goto quit:可以跳出深层嵌套的循环;或者将所有循环放进一个函数,用return 离开此函数。

for循环把所有控制循环的条件都放在一个括号,方便直观。

 1 switch(expression ):
 2 
 3       case  1: //expression ==1
 4 
 5                   printf("OK!") 
 6 
 7                   break//直接跳到switch情况列表的结尾
 8 
 9       case  2: //expression ==2
10 
11                   printf(" NOT OK!")
12 
13                   break14 
15       default:
16 
17                  printf("no pregived expression! ")
18 
19                  break//本身是末尾,加不加不影响跳出,但是加上为了维护方便。防止再加一个判断时出错。
1 int   *a    //
2 int*   a    //  ×

因为这个*和变量名a是一体的,表示a是个指针变量。同样int *a, b表示声明一个指针变量a和一个整型变量b

如果 int *a =  5 ,则意味着将5这个整型数据所在的内存地址的起始位置赋值给整型指针a。int *a指的是一个指向整型数据的指针,中心是指针,而不是内存地址数据。此时int *a ==5;  则a == &5,内存起始地址;且*a == 5。

这里其实很巧妙,对于指针取内存数据的操作就是 *Pointer。而声明指针时如果看成对指针取内存数据那么*a的类型就是int类型。

获取指针变量的地址:&p    这个是指针对象自身的内存地置,不是它指向的内存的地址。

指针也是变量。变量是什么?一段存放数据的内存空间。

只不过指针变量的值比较特殊,存放的是另一个变量的内存地址。那么指针的内存地址和指向变量的内存地址有什么关系??屁关系没有。

1 int a = 5
2 int *b =&a   

左边赋值的都是给变量对应的内存空间存放的数据进行初始化。
如果a是普通变量,那么要用普通常量赋值;如果a是指针,那么根据指针的 定义,要用一个内存地址给a赋值。
这是给变量(内存)赋值的原则。

借用一般变量的性质,比如 int a;a =5。即可以将变量内存体存放的数据直接赋值给变量名。那么,同样的对于指针,则a = 0X11234.指针内存内存放的是一个地址也即一串数字,也可以直接左值赋给指针变量名。

关于指针相关的常量:

1 int  const  *p    //定义一个指向常量数据的指针,指针的值可以修改,但是它指向的数是个常量。
2 int *const p      //定义一个指针,这个指针的值不能修改(指向地址不能修改),但是指向的内存地址存放的数据可以修改。
3 int const * const p   //定义一个指针,指向的地址不能修改,且地址内存的数据也不能修改。

C语言不允许嵌套注释。

函数原型的声明:参数名字不是必须的,更不用和定义时的形参名一致,也不必与函数实际调用时的传递的实参匹配。但是原型的参数不能有两个完全相同。

内存的结构:内存不止分为堆和栈,还有另外3个区:https://www.cnblogs.com/fengyv/p/3789252.html(其中堆栈画反了)
|-----------|
|     栈     |    存放函数的参数和局部变量,编译器自动分配释放(整个内存的末尾),先进后出,很小一共只有几M.便于递归。
|-----------|     连续内存 Stack
|      |      |
|     |/     |      函数的实参必须在堆栈中,函数是传值的,因此static不能修饰函数形参。
|     /|     |
|      |      |   局部变量都是运行到代码块那里时才会创建,代码块执行完就销毁
|-----------|   而静态变量是程序运行前创建,整个程序执行期间存在。程序执行期远大于某个函数或代码块执行期!

|------------|

|    堆      |      堆区(Heap)由程序员申请和释放;一般有几G,动态伸缩,malloc变大,free变小 。内存泄漏就是指这一块。

|------------|     链表(非连续内存)
|------------|   
|------------|
|--初始化-|      初始化的全局变量及局部静态变量内存区( ↑以上Data段:包括堆、栈和静态数据区,其中还有常量)|              | 

|------------|     

|------------| 
|-未初始化|    未初始化的全局变量及局部静态变量内存区 (Bss段

|------------| 
|------------|
|--正文段-|     代码的二进制文件Text段:可执行文件中的指令)
|------------|

程序执行时,text段和data段都在可执行文件中,由系统从可执行文件中加载;而BSS段不在可执行文件中,由系统初始化。

缺省链接属性:(链接:编译好之后去链接成整体时反应出的就是可见不可见范围)

  • external:只有函数体外的变量,或函数缺省才是external,全局实体
  • internal:本源文件中都是指向同一个实体;不同源文件分属不同实体。
  • none:函数体内的变量链接属性缺省为none属性,多个声明总是被当做不同实体
  • 对于通过static或extern更改变量的链接属性,只有第一次起作用,第二次及以后不再起作用。而且这两个关键字仅在声明时需要。
  • 注意:对于一个函数默认是external,引起是全局实体,只要在其他源文件中引入函数原型(即声明)即可调用。但是如果函数返回值是整数,那么其他源文件不用声明也能调用。

关于static关键字:(两种完全不相关的作用和场景)

  1. 在用于代码块内部变量声明时,指更改参数存储类型为局部变量,整个程序运行期间存在。  ------存储类型
  2. 在用于函数体外的函数定义或变量声明时,指此函数或变量可见范围仅在声明它们的本源文件内。------链接属性(不加static则取默认类型为external,加了就变为internal。但是如果本文件用其他文件中的变量,最好还是加上extern arg,增加可读性)

相对应的是extern关键字

  1. 具有extern关键字的实体称为全局实体,即对所有的源文件的所有函数可见。只要不是代码块或函数定义内部,缺省属性就是extern
  2. extern用于声明函数体内的参数时,是告诉编译器这里我要引用其他源文件中声明的的外部(全局)变量,存储于静态内存,具有external链接属性。(函数内部的缺省链接类型是internal,存储于堆栈,)
原文地址:https://www.cnblogs.com/Henry-ZHAO/p/12725128.html