赫斌C语言全案文,自用笔记,给后来者一点思路

1、CPU 内存条 硬盘 显卡 主板  显示器 之间的关系

比如在硬盘上的一部电影,CPU如果想调用它,就要把硬盘上的数据调用到内存条(CPu不能直接调用硬盘上的数据),CPU处理调用在内存条的数据,把一些数据变成图像(图像通过显卡在显示器显示出来),一些变成声音(CPU把数据发送到声卡,声卡把数据发出声音出来)

CPU、显卡、声卡等全部都是插在主板上的,主板提供了一个中间的传输的设备,如何有效的走到一起的

2、HelloWorld程序如何运行起来的

答案:软件请求操作系统去执行,操作系统调用CPU,CPU再把结果返回到软件,软件在显示器上就可以看到结果了

# include <stdio.h>

//通过编译和链接这两个步骤来生成一个  .exe的可执行文件(由VC++生成)                    所有的软件进行都是建立在操作系统之上的

//按!有CPU来执行,程序VC++不能直接执行  .exe文件

//按!按钮时,软件会请求操作系统,由操作系统执行 .exe文件

int main(void)

{

printf("欢迎来到C世界!\n");//printf含义:打印输出

return 0;

}  

3、什么是数据类型

编程的基础就是解决问题:

第一步:把数据保存到计算机里头去(图是管理系统:把图书信息保存在计算机里面)(人事管理系统:那个是老板,那个是经理,哪个是领导,那个是员工。。。把他们之间的关系保存在计算机里头去)------------------------数据的存储

数据存储就要进行数据分类、归类(数学:对数字进行分类:整数、实数、字符)

基本类型数据(不能在进行分割)

整数(C语言和数学是一样定义的)

        整型      --int       4个字节

        短整型        -- short  int         2个字节

       长整型        --long  int            8个字节

   

实数(C语言叫浮点数,含有小数点这些数字)(叫浮点数,属于计算机内部编码的问题,计算机不能定点存储,通过浮点来存储的)

单精度浮点数 --float   (4字节)

双精度浮点数 --double (8字节)  (对于3.3来说,用double浪费内存了)有限空间存储更多数据

字符(C语言和数学是一样定义的)(abcde)

用char表示               (1个字节)

字符(单个字符)

所有字符用一个字节就可以表示出来了

字符串--  一系列字符的组合(字符串不能用char表示,用字符数来表示)(string是C++和Java里头的)

复合类型数据

     结构体

     枚举

     共用体(现在没人用共用体了

4、什么是变量

变量就是一个容器(内存地址,内存中的一段存储空间),把数据保存在计算机里,要通过变量来保存,系统通过变量来直接存储我们要存储的数据(变量自动查询地址)

# include <stdio.h>

 //执行int i后,请求操作系统,在内存条找到一个空闲的,没有被其他程序占用的存储单元(格子),把它当作变量i来使用(格子与字母i产生关联)

int main(void)

{

int i;  //只定义了存储空间

i = 3;  //3最终是存放在内存中,程序终止之后3所占的空间被释放掉(此程序不再占用i对应 的内存空间),不然空间一下就满了(把3放在与i关联的格子里去了)

printf("i = %d\n", i);

return 0;

}

5、CPU 内存条  VC++6.0 操作系统 之间的关系

最终是软件请求操作系统在我们内存条里面分出一段存储空间(系统分配空间),这个空间以变量字母i产生关联,以后使用的字母i,实际上使用的就是字母i对应的空闲存储空间(不能说是3,i可以改)

6、变量为什么必须的初始化(初始化就是赋值)

初始化就是赋值的意思

1高电平  //通过电压产生

0低电平

# include <stdio.h>

int main(void)

{

int i ;     //只定义了内存空间,如果以前i的空间遗留的是以前软件存储的垃圾数据还在保留着,如果i不初始化,i里面就是垃圾值(随机值,不确定值),也叫添充字,微软公司,如果发现i空间是垃圾值,没有初始化,它会自动放一个添充字  (-8……………6很大的数字,系统检测会直接认为没有进行初始化

//软件运行结束后,操作系统会回收内存空间给其他程序使用(但操作系统不会清空上一个软件在该空间遗留下来的数据-----垃圾数据)(系统分配表)

printf("i = %f\n", i);  //int %d  char %c  flaot %f double %lf  long int %ld      //只定义就把i输出了

return 0;

}

7、如何定义变量

数据类型   变量名  = 要赋的值;

等价于

数据类型  变量名;

变量名  =要赋的值;

8、什么是进制   (十进制:逢十进一  。。。。)

十进制就是逢十进一

%d表示以十进制输出

%x或%X表示以十六进制输出

%o表示以八进制输出

9、常量在C语言中是如何表示的

整数:

        十进制     传统的写法

         十六进制         前面加ox或OX

         八进制:          前面0(加零)   注意事数字零不是字母O

浮点数

   传统的写法

   科学计数法

   float  x = 3.2e3  //x的值就是 3200

   float  X =123.45e-2    //x的值1.2345

字符

  单个字符用单引号括起来

  ‘A’表示字符A

   

   ‘AB’错

   “AB”对

  字符串用双引号括起来

  “A”正确,因为“A”代表了‘A’ ‘\0(零)’的组合  (零无意义) 

  

10、常量以什么样的二进制代码存储在计算机中

IEEE754标准怎么去实现的

‘A’---》65---》补码(字符A对应的二进制代码是几)(先告诉程序:A是用那个整数去存储(叫ASCLL码:A用哪个整数去表示,B用哪个整数去表示,‘?’用哪个整数去表示)

65怎么转换成二进制:通过补码,整数用补码表示的(可以认为规定了一个存储方式)

11、代码的规范化

代码的可读性更强[容易让自己和别人更清楚的看懂程序]

使程序更不容易出错

# include <stdio.h>

int main(void)

{

//定义变量

//对变量进行操作

//输出值

return 0;

}

12、什么是字节

字节就是存储数据的单位,并且是硬件所能访问的最小单位(01010101)(硬件只能精确到字节,不能精确到位)(1字节=8位)

想控制到某一位,通过软件的位运算符,硬件通过地址总线确定字节

1K=1024字节

1M=1024K

1G=1024M=1*1024*1024*1024*8

13、不同类型数据之间相互赋值的问题

补码

只用补码在现实当中才被运用起来

14、什么是ASCLL

ASCLL不是一个值,而是一种规定

ASCLL规定了不同的字符是使用哪个整数值去表示的问题

它规定:

       ‘A’--65   //A在ASCLL下用65去标记、表示

        ‘B’--66

         ‘a’--97

           'b'--98

           '0'--48   零

15、字符的存储[字符本质上与整数的存储方式相同

基本的输入和输出函数的用法(两个

                 printf()--将变量的内容输出到显示器上

                 四种用法

                              1、printf("字符串\n ");    //字符串也可以是汉字

                              2printf("输出控制符",输出参数);

                              3、printf(“输出控制符1          输出控制符2………………”,输出参数1,输出参数2……………………..); //输出控制符  %d  %f  %c

                             //一个控制符,针对一个输出参数

                             4、printf("输出控制符   非输出控制符",输出参数); //%开头都是输出控制符

                                   输出控制符包含如下:

                                       %d     只读整型       --int

                                       %ld                 --long int

                                       %c                --char

                                       %f                --float

                                      %lf                --double

                                       %x(或者%X或者%#X或者%#x)   %#X最好,推荐使用 --int,long int, short int

           %0                 --int,long int, short int

           %s                 --字符串

                                      为什么需要输出控制符

                                     1、01组成的代码可以表示数据也可以表示指令        (0101011000代码时,它表示的是电影还是数字还是一个字符或者图片,都是不清楚的,本身是没有含义的,关键在于如何去解读

                                     2、如果01组成的代码表示的是数据的话,那么同样的01代码组合以不同的输出格式输出就会有不同的输出结果;需要输出控制符去指定它

                scanf()   //输入,将键盘上的字符或者数据给它存入变量里头

              【通过键盘将数据输入到变量中】

               两种用法:

                       用法一:  scanf("输入控制符",输入参数);                 在C语言中,输入、输出控制符都是%d   %f   %c,&i为输入参数

                      功能:       将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

               

                      用法二:  scanf("非输出控制符   输入控制符",输入参数);                                   

                      功能:       将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中

                                       非输入控制符必须原样输入

运算符

               算术运算符

                          +  -  *  /   %

             

              关系运算符

                         >     >=  <    <=       !=(不等于)      ==(等于)

            逻辑运算符

                          !(非)         &&(并且)         ||(或)

                          !真          是假

                          !假         是真

                       &&        

                       &&        

                      &&         

                      &&         

C语言中对真假的处理

                      只要K=非零的字符    ------就是真的

                      赋值的结果为零,就是假的

                      ||             

                      ||             

                      ||             

           赋值运算符

                        =   +=     *=      /=        -=

        优先级:

             算术>关系>逻辑>赋值

不用记

附录的一些琐碎的运算符知识

    1     自增 自减 三目运算符 逗号表达式

         自增【或自减】

         分类:

                   前自增   --      ++I

                   后自增   --       i++

                  前自增和后自增的异同

                  相同:

                           最终都是使i的值加1

                  不同:

                           前自增整体表达式的值是i加1之后的 值

                          后自增整体表达式的值是i加1之前的 值

             

                为什么会出现自增

                            代码会更精练

                           自增的速度更快 ++i直接在CPU寄存器进行处理

            学习自增要明白的几个问题

                         1、我们编程时应该尽量屏蔽掉前自增和后自增的差别

                         2、自增表达式最好不要作为一个更大的表达式的一部分来使用

                               或者说

                             ++i和i++单独成一个语句,不要把它作为一个完整复合语句的一部分来使用,不要写成很长的例子

                             如:

                              int m = i++ + ++i + i + i++;      //这样写不单是不规范的代码,而且是不可移植的代码 ,不可移植:换个机器结果就不一样了

                                 //不知道i++是否已经加1 

                                //让别人看起来头疼的代码是不好的代码

                        只有顺序点  ,   ()    ;  这三个才可以明确的知道操作是否生效

自减同上

2 三目运算符

             A ?B :C //三目运算符一般不太会用,没有下面的逻辑清晰

             等价于

                 if(A)

                    B;

                 else

                    C;

Int m = 3>2 ? 5: 6;

3、逗号表达式

      格式:

   ( A , B ,C ,D)

            功能:

                        从左到右执行

                         最终表达式的值是最后一项的值:D的值

数组:(不是特别重要)

                              为什么需要数组

                                               为了解决大量同类型数据的存储和使用问题

                                               为了模拟现实世界

                                               用数组可以模拟现实世界

                                              int a[25] ; //一条直线

                                              int a[8][6]; //模拟一个平面事物,一般当作八行六列,也可六行八列

                                              int a[3][4][5]; //三维,一个平面加个高度

                                              int a[3][4][5][6];//四维,在三维基础上加个时间

                                        数组长度是个死的值,不能改变

                                        通常不自己定义数组,使用别人写的工具

                                       add(  )加

                                       sort( )排序

                              数组的分类

                                             一维数组

                                                        怎么定义一维数组

                                                                     n个变量连续分配存储空间

                                                                     所有的数据类型必须相同,不可能第一个元素是int,第二个元素是float型

                                                                     所有变量所占的字节大小必须相等

 

                                                         例子:

                                                                int a[5];

                                                               一维数组名不代表数组中的所有元素,

                                                              一维数组名表达数组第一个元素的地址 

                                                         有关一维数组的操作

                                                         初始化

                                                                 完全初始化

                                                                       int a[5] = {1, 2, 3, 4, 5};

                                                                 不完全初始化,未被初始化的元素自动为零

                                                                       int a[5] = {1, 2, 3};

                                                                 不初始化,所有元素为垃圾值

                                                                      int a[5];

                                                                 

                                                                 清零

                                                                      int a[5] = {0};//全部为零

       

                                                                 错误写法:

                                                                      int a[5];       //只有在定义数组的时候  [],里面的表示数字,其他地方的[],里面都表示下标,下标表示元素的位置

                                                                      a[5] = {1, 2, 3, 4, 5};   // 错误写法,  a[5]元素不存在,只有 a[4], [5]:第六个元素

                                                                       只有定义数组的同时才可以整体赋值,

                                                                       其他情况下整体赋值都是错误的

 

                                                                       int a[5] = {1,  2, 3, 4, 5};

                                                                       int a[5] = 100;   //error 因为没有a[5]这个元素,最大只有a[4]

         

                                                                       int a[5] = {1,  2, 3, 4, 5};

                                                                       int b[5];

                                                                 如果要把a 数组中的值全部赋值给b数组

                                                                        错误的写法:

                                                                                  b=a;  // error  数组名字a代表的是数组第一个元素a0的地址,数组名字b代表的是数组第一个元素b0的地址

                                                                         正确的写法

                                                                                   for(i=0; i<5; ++i)

                                                                                   b[i] = a[i];

                                                         赋值

                                                        

                                                         排序

                                                         求最大、最小值

                                                         倒置

                                                         查找

                                                         插入

                                                         删除

                                            二维数组

                                                         int a[3][4];

                                                        总共是12个元素,可以当作3行4列看待,着12个元素的名字依次是

                                                        a[0][0]  a[0][1]  a[0][2]  a[0][3]

                                                        a[1][0]  a[1][1]  a[1][2]  a[1][3]

                                                        a[2][0]  a[2][1]  a[2][2]  a[2][3]

                                                        a[i][j] 表示第i+1行第j+1列 

                                                       int a[m][n];  该二维数组右下角位置的元素只能是a[m-1][n-1]

          

                                                       初始化

                                                                     int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}

                                                                     int a[3][4] ={

                                                                                         {1, 2, 3, 4},

                                                                                         {5, 6, 7, 8},

                                                                                         {9, 10, 11, 12},

                                                                                         };

    

                                                      输出二维数组的内容:

            

int main(void)

{

int a[3][4] = {

{1, 2, 3, 4},

{5, 6, 7, 8},

{9, 10, 11, 12}

};

 

int i, j;

 

//输出数组内容

for(i=0; i<3; ++i)// 内循环每执行4次,此循环执行1次

{

for(j=0; j<4; ++j) 

{

 

a[i][j];

printf("%d   ", a[i][j]);  //加两个空格

 

}

printf("\n");

}

return 0;

}

/*

1   2   3   4

5   6   7   8

9   10   11   12

Press any key to continue

*/

 

                       对二维数组排序

                       求每一行的最大值

                       判断矩阵是否对称

                       矩阵的相乘                

    多维数组

                           是否存在多维数组

                          不存在

                           因为数组是线性一维的

                           n维数组可以当作每个元素是n-1维数组的一维数组,只只要把这句话说给导师就行

                                                比如:

                                                     int a[3][4];

                                                              可以当作每个元素都含有3个小元素的一维数组

                                    只不过每个元素都可以分成4个小元素  {1, 2, 3, 4}

                              int a[3][4][5]

                                    可以当作每个元素都含有3个小元素的一维数组

                                    只不过每个元素都是[4][5]的二维数组,四行五列

                             int a[3][4][5][6] 

                                    可以当作每个元素都含有3个小元素的一维数组

                                    只不过每个元素都是[4][5][6]的三维数组

                                   

例子:

# include<stdio.h>

int main(void)

{

int a[5] = {1, 2, 3, 4, 5}; //元素就是变量

//a是数组的名字,5表示素组元素的个数,并且着5个元素分别用a[0] a[2] a[3] a[4]

int i;

for(i=0; i<5; ++i)

printf("%d\n", a[i]); //a[i]表示第i+1个元素

printf("%d\n", a[100]);//垃圾值

return 0;

}

/*

结论:

----------------------------------

1

2

3

4

5

Press any key to continue

a[5]定义了5个变量,不过数组中的变量不叫变量叫元素

单个定义的叫变量,数组一定义就定义多个,叫元素,本质和变量一样只是换个词

----------------------------------

*/

越往后越不重要,琐碎的东西

 

学习找不到出路

不搞技术搞其他的挣不了钱

做生意也不行 当官也不行

很幸运

 # include <stdio.h>

int main(void)

{

//printf("哈哈!\n");  //\n表示换行

//        int i = 10;

//        printf("%o\n", i);  //d是十进制,i对应的是10的二进制代码    qqqq                

int j = 3;

int k = 5;

//printf("%d %d\n", j, k);  //OK

//printf("%d\n", j, k);  //error 输出控制符和输出参数的个数不匹配

//一个控制符,针对一个参数

printf("i = %d, j = %d\n", j, k);

return 0;

}

除法与取模运算符

/

两个数都是int,则商就是int,如商又小鼠,则结果又小数部分

%取余

结果只与前边的整数有关

前边的整数为正,则整除后的余数为正

否者为负

流程控制(第一个重点)

流程控制可以让我们自个看懂程序,是我们自学语言的能力的一大技能

1、什么是流程控制

           程序代码执行的顺序:代码不一定一行一行去执行,有可能跨几行执行或者倒过来执行

           从上往下的顺序

           中间有些代码不执行,直接跳过执行下一个

2、流程控制的分类

         

用循环、顺序、选择组合在一起

就能解决现实世界任何复杂的问题

  顺序执行

           一行行去执行

        

  选择执行

         定义

               某些代码可能执行,也可能不执行,有选择去执行某些代码

        分类

              if            不是循环            

                                       if比switch更重要的多

                     1、if最简单的用法

                         if(表达式)     //表达式是否是正确

                                           语句

                          功能:

                                    如果表达式为真,执行语句

                                    如果表达式为假,语句不执行

                            

                     2、if的范围问题

                           1、

                                 if(表达式)

                                                  

                                        语句A;

                                        语句B;

                                        

                               解释if默认只能控制语句A的执行或不执行

                                         if无法控制语句B的执行或不执行

                                        或者讲:语句B一定会执行(不论表达式是否是真假)

                         

                                      if(表达式)

                                                   {

                                        语句A;

                                        语句B;

                                         }

                               解释:{        }起来,此时if可以控制语句A和语句B

      3、if…else..的用法

                     4if…else   if…else… 的用法

                         if(1)

                            A ;

                        else if (2)

                            B ;

                         else if(3)

                            C;

                         else()

                            D;

        

                     5、c语言对真假的处理

                     非零就是真

                     零就是假

                     真用1表示

                     假用0表示

                     6、if举例--求分数的等级

                       

                     7、if的常见问题解析

                          1、 if的常见问题解析

                                       if(3 > 2);

                                        等价于

                                      if (3 > 2)

                                          ;  //这是一个空语句

                                 if (表达式1)

                                    A;

                                 else if (表达式2)

                                     B ;

                                  else if (表达式3)

                                    C;

                                 这样写语法不会出错,但逻辑上有漏洞

 

           

                                

                                   if (表达式1)

                                    A;

                                 else if (表达式2)

                                     B ;

                                  else if (表达式3)

                                    C;

                                   else(表达式4)     //7行

                                    D;

                                   这样写是不对的,正确的写法是:

                                     要么去掉7行的(表达式4)        

                                     要么在else 后面加 if                               

Switch

          把电梯程序看懂就OK了

# include<stdio.h>

 

int main(void)

{

int val;

 

//模拟一个电梯

printf("请输入你要进入的楼层: ");

scanf("%d", &val);

 

switch (val)  //switch语句放val看和下面那个语句的值相等,执行那个语句

{

case 1: //val如果和1相等,执行这层语句

printf("1层开!\n");

//        break;

case 2:

printf("2层开!\n");

break; //breakswitch中止

case 3:

printf("3层开!\n");

case 4:

printf("4层开!\n");

break;

case 5:

printf("5层开!\n");

break;

default:   //默认的意思,val和上面或下面层数都不相等,执行这一语句

printf("还没有盖到这一层!\n");

break;

}

 

printf("已到达!\n");

 

return 0;

}

 

/*

总结:

----------------------------------

有选择去执行,switch也叫选择

从上往下去执行,一旦找到程序入口,执行输出

switch 是选择不是循环,如果switch中出现break是,中止switch语句,跳出switch语句,执行下一个单独语句

----------------------------------

*/

循环执行

          在某行代码上可能会执行几次或几十、上百次循环操作

          定义:

                      某些代码会被重复执行 

          分类

                  for

1、格式:

                     for1 2 3

                                语句A 单个for循环的使用

                                 B//4

 

整体是两个语句,1  2  3  是第一个语句,

4是第二个语句

 

 

多个for循环的嵌套使用     0.            1->2->4->5->A->6->5->A->6->5(结束)->3(标志整个大整体结束)

                                                         ->2->4->5->A-6->5->A->6->5(结束)->3->2(结束)->B

    for(1; 2; 3)

                for(4; 5; 6;)

                      A;

                      B;  //执行B后,上面for循环不执行

 

 

    for(1; 2; 3)

                for(4; 5; 6;)

{

                      A;

                      B;  //执行B后,上面for循环不执行

}

 

   for(7;  8;  9)

   for(1  ;  2;   3)

{

A;

B;

For(4;  5;  6)

C ;

}                //黄色一个语句

 

还是一个语句,for 默认控制一个语句

先执行内循环 

3、范围问题

4、举例

1+2+3+…+100

for(i=1; i<=100; ++i) //从1开始循环100次,for默认只能控制一个

sum = sum + i;

顺序: 1   、2   、3    、4

         2判断i是否成立

         4执行完,执行3

          2在判断i是否成立

。。。。。。。。。。。。。。。。。。。

i++是先赋值,在自增; ++i是先自增后赋值

1、为什么要给sum 赋值 =0  ,因为sum不赋值的话,本身就是一个垃圾值,垃圾值加1还是垃圾值

饭后小甜点:

求1到100之间的奇数之和

 

求1到100之间的奇数的个数

 

求1到100 之间的奇数的平均值

 

求1到100之间的奇数之和与偶数之和,在求1到100之间的偶数之和

                  while

                           1、执行流程(或顺序)

                                           格式:

                                               while(表达式)

                                                             语句;

                           2、与for的相互比较

                              for和while可以相互转换

                             for1 2 3

                                        A

                            等价于

                             1

                             while2 //2用来判断条件是否还需继续执行

                                      {

                             A

                             3

                              }

//for和while虽然是一模一样等价的,但是for逻辑上更强

                         while和for可以相互转化

                         但for逻辑性更强,更不容易出错,推荐多使用for

 

                           3、while举例

                                从键盘输入一个数字,如果该数字是回文数

                                则返回yes,否则返回no

                               回文数:正着写和倒着写都一样

                               121             1222221

                           4、什么时候使用while,什么时候使用for

                              没法说,用多了自然而然就知道了

             

                              do…while

                                               格式:

                                                      do{

                                                           ………….

                                                           }while(表达式)

                                                        //先执行内部语句,再进行判断,所有do一定会执行一次

                                                        while(表达式)

                                                        {

                                                      ……………..

                                                         }

                                do…while…并不等价于for,当然也不等价于while

                             主要用于人机交互

                                    一元二次方程

            

                            breakcontinue

                                   break如果用于循环时用来终止循环

                                   break如果用于switch,则是用来终止switch

                                   break不能直接用于if,除非if属于循环内部的一个子句

例子:

# include<stdio.h>

int main(void)

{

int i;

/*        switch(2)

{

case 2:

printf("哈哈!\n");

break;

}

*/

for(i=0; i<=3; ++i)

{

if(3>2)

break; //一次都没有执行

printf("嘿嘿!\n");    //printf永远都不会输出,break虽然是if内部的语句,但break却是用来终止外部的for循环

}

return 0;

}

例子:

# include<stdio.h>

int main(void)

{

int i, j;

for(i=0; i<3; ++i)

{

for(j=1; j<4; ++j)

break;   //break只能终止距离它最近的循环

printf("我是天下第一!\n");

}

return 0;

}

/*

在VS6.0++中的输出结果是:

------------------------------

我是天下第一!

我是天下第一!

我是天下第一!

Press any key to continue

------------------------------

*/

break很重要,break终止整个循环体

在多层switch嵌套中,break只能终止距离他最近的switch

 

 

 

  switch

   

          有选择去执行代码,跳跃执行

 

例子:

# include<stdio.h>

int main(void)

{

int x, y, a, b;

x=1, y=0, a=0, b=0;

switch(x) //第一个switch

{

case 1:

switch(y) //第二个switch

{

case 0:

a++;

break; // 终止的是第二个switch

case 1:

b++;

break;//终止的是第一个switch

}

b = 100;

break;

case 2:

a++;

b++;

break;

}

    printf("%d %d\n", a, b);

return 0;

}

/*

在VS6.0++中的输出结果是:

---------------------------

1 100

Press any key to continue

---------------------------

*/

Continue  不是重点

            用来跳过本次循环余下的语句,

            专区判断是否需要执行下次循环

例子:

1、

for(1; 2; 3)

{

A;

B;

continue; //如果执行该语句,则执行完该语句后,会执行语句3,C和D会直接被跳过,C的D不会被执行

C;

D;

}

2、

1

while(2表达式//执行下面语句后,执行表达式

{

A;

B;

3

continue;   //continue只终止循环一次

 //如果执行该语句,则执行完该语句后,会执行表达式,C和D会直接被跳过,C的D不会被执行

C;

C;

D;

}

3、

# include <stdio.h>

int main(void)

{

int i;

char ch;

scanf("%d", &i);

printf("i = %d\n", i);

//.......

while ( (ch=getchar()) != '\n')  //工具得加(),getchar()等待用户从键盘上输入字符:get(char)赋给ch,只要ch不是换行符\n,就continue继续返回到getchar()判断是否正确

//把用户输入的垃圾数字全部夺过来,只要不是换行符

continue;

int j;

scanf("%d", &j);

printf("j = %d\n", j);

return 0;

}

# include <stdio.h>

int main(void)

{

int i;

char ch;

scanf("%d", &i);

printf("i = %d\n", i);

//.......

while ( (ch=getchar()) != '\n')  {//工具得加(),getchar()等待用户从键盘上输入字符:get(char)赋给ch,只要ch不是换行符\n,就continue继续

//把用户输入的垃圾数字全部夺过来,只要不是换行符

 

 

continue;

 

}//对遗留数据循环进行读取,这样就可以清除缓冲中的剩余字符

 

//当抽出来的字符不是\n是,()内为真,把这个字符消耗掉,并比较下一个

//垃圾信息就可以被循环消化掉

//可以理解为我们输入一个消耗品

//直到我们敲击回车键(等价于\n,结束while循环

 

printf("%c", ch);  //ch

int j;

scanf("%d", &j);

printf("j = %d\n", j);

return 0;

}

# include <stdio.h>

int main(void)

{

int i;

char z,ch;

scanf("%d", &i);

printf("i = %d\n", i);

//.......

while ( (ch=getchar()) != '\n')  {//工具得加(),getchar()等待用户从键盘上输入字符:get(char)赋给ch,只要ch不是换行符\n,就continue继续

//把用户输入的垃圾数字全部夺过来,只要不是换行符

       z  = ch;  //除非,ch赋值给z,否则消失,在表达式里头,不做输出

continue;

}//对遗留数据循环进行读取,这样就可以清除缓冲中的剩余字符

//当抽出来的字符不是\n是,()内为真,把这个字符消耗掉,并比较下一个

//垃圾信息就可以被循环消化掉

//可以理解为我们输入一个消耗品

//直到我们敲击回车键(等价于\n),结束while循环

printf("z=%c", z);  //无ch值

int j;

scanf("%d", &j);

printf("j = %d\n", j);

return 0;

}

列题:

什么是素数,只能被1和自身整除的数

 

回文数: 1221   121   这些个正着写和倒着写都一样的数

 

编写实现求一个是十进制数字的二进制形式

 

求一个数字的每位是奇数的数字取出来组合性成果的新数字

 

求一个数字倒过来的数字

如何看懂一个程序,分三步:

1、流程                 9798课很重要

 

2、每个语句的功能

 

3、试数                             -------这三个能重要,能理解C语言的整个过程。

方法:

对一些小算法的程序

                     尝试自己去编程解决它,大部分都自己无法解决

                     如果解决不了,就看答案

                     关键是把答案看懂,这个要花很大的精力,也是我们学习的重点

                     看懂之后尝试自己去修改程序,并且知道修改之后程序的不同输出结果的含义

                     照着答案去敲

                     调试错误

                     不看答案,自己独立把答案敲出来

                     如果程序实在无法彻底理解,就把它背会

强制类型转化

             格式:

                  (数据类型)(表达式)

            功能:

                   把表达式的值强制转化为前面所执行的数据类型

             例子:

                    (int)(4.5+2.2)最终值是6.7==》6

                      (float)(5)              最终值是   5.000000

浮点数的存储所带来的问题

                      float和double都不能保证可以精确的存储一个小数

 

举例:

          有一个浮点型变量X,如何判断x的值是否是零

            //if (0 == x)

            // 是

               if(|x-0.000001|<0.000001)

               是

             if()

            else

              不是

           为什么循环中更新的变量不能定义成浮点型,因为浮点型是个非准确存储。

           浮点型只是不能保证准确存储,有些数字还是能准确存储的

            for(I; i<=100; ++i)

            假如i=100.000001,就不能正常输出i=100的值,float型会在循环结构中把i误差放大

           循环结构一般不定义浮点数

饭后小甜点:

比如 : 两个变量进行互换 a,b

             定义一个变量t

T  = a;

A  = b;

B = t;

函数【C语言的第二个重点】

 printf是个函数

例子:

# include<stdio.h>

//下面是个工具,max是个函数

//函数的用法:如果在很多地方,它要执行的功能是相似的,只不过所针对的数据不一样

//max是函数的名字,它有两个变量i和j,只不过在函数有专业词叫形参,就好比数组的变量叫元素,i和j是形式参数,简称形参   void表示函数没有返回值

//函数是为相似的,同类型,大量的数据设计的

//将来无论那个程序需要max(int i ,int j)功能都可以使用它,只要哪个程序想要求两个数据的最大值都可以使用它,比如printf, scanf

//函数可以处理的数据是不一样的,但是对数据的操作是一样的

//使用函数可以避免使用大量重复性代码,减少工作量

void max(int i ,int j)  //max(a,b)没有错误,赋值给(int i ,int j),函数执行max函数

//执行完max(a,b),(int i ,int j)空间会释放掉,使用完再分配,使用完再分配......,还有没有一个语言可以保证分配使用的空间是同一个空间

{

if (i>j)

printf("%\n",i);

else

printf("%d\n", j);

}

//上面函数是从main函数进入的

//int表示return o;返回一个整型值 0,void表示它不接收任何参数,不用管他

//程序一定是main函数进入的

//程序从main函数调用其他函数,也一定从main函数推出,调用main函数完后,一定返回main函数,为了再次使用

int main(void)

{

int a, b, c, d, e, f; //分配六个变量

a = 1, b = 2, c = 3, d = 9, e = -5, f = 100;//给六个变量赋值

//max工具使用上面

max(a,b); //第一步它会先检测max里面的几个字符有没有对应的函数,第二步它发现a,b是两个整型变量,已经有两个形参,它就认为这个语句可以执行了,执行完这个语句,执行下个语句

//把a的值发送给上面函数的int i 的值,把b的值发送给上面函数的 int j的值,然后程序会跳到max函数内部去执行

max(c,d);//下个语句

max(e,f);

/*

if (a>b)

printf("%d\n", a);

else

printf("%d\n", b);

if (c>d)

printf("%d\n", c);   //\n:增加可读性

else

printf("%d\n", d);

if (e>f)

printf("%d\n", e);

else

printf("%d\n", f);

     //代码操作是一样的

 */

return 0;

}

为什么需要函数

                     避免了重复性操作

                     有利于程序的模块化(其实这就是面向过程的思想)   

                  

                       

                           

           

什么叫函数

2021年5月17日

14:10

什么是函数

   逻辑上:能够完成特定功能的独立的代码单元(代码块)

  物理上:能够接收数据【当然也可以不接收数据】

                能够对接收的数据进行返回

                能够将数据处理的结果返回【当然也可以不返回任何值】

 

总结:

                函数是个工具,它是为了解决大量类似问题而设计的

                不是为了某个特定问题设计的

                函数可以当成一个黑匣子

例子:

# include<stdio.h>

//被调函数

int f(void)  //括号中的void表示函数不能接收数据 int表示函数返回值是int类型

{

return 10;  //向主调函数返回10

}

void g(void)//函数名前面的void表示该函数没有返回值

{

//return 0; //error,void表示没有返回值,与此函数行首的void相矛盾

}

//一个函数可以有返回值,也可以没有返回值(可接收和不可接收数据)

//主调函数

int main(void)

{

int j = 88;

j = f();

//j = f(8); //错误写法 ,int j = f(8)意味着int f(void)()里面要写一个整形但是里面是void

printf("%d\n", j);

//j = g();//error,g()函数没有返回值,不能赋值给j

return 0;

}

如何定义函数

                    函数的返回值 函数的名字(函数的形参列表)

                 {

                         函数的执行体

                    }

1、函数定义的本质是详细描述函数之所以能够实现某个特定功能的具体方法

2、return 表达式,含义:

        1>终止被调函数,向主调函数返回值表达式的值

        2>如果表达式为空,则只终止函数,不想主调函数返回值任何值

        3>break是终止循环和switch的,return是用来终止函数的

         例子:  如果是void则return后面不加值,如果是数据类型的话,return后面加一个和它类似的数据类型

void f()

{

return;//只用来终止函数,不向主调函数返回任何值

}

Int f()

{

Return 10;//终止函数,并向主调函数返回10这个值

}

3、函数返回值的类型也称为函数的类型,因为如果  函数名前的返回值类型和函数执行体中的return 表达式;中表达式的类型不同的话,则最终函数返回值的类型 以函数名前的返回值类型为准

例子:

# include<stdio.h>

int f()

{

return 10.5; //因为函数的返回值类型是int,所以最终f返回的是10而不是10.5

//函数的类型以此函数行头的int为准

}

int main(void)

{

int i = 99;

double x = 6.6;

x = f();

printf("%lf\n", x);

return 0;

}

函数的分类

               有参函数和 无参函数

              有返回值 和 无返回值函数

             库函数(main)  和用户自定义函数(int f() ,  int max()) //库函数系统提供的

               值传递函数 和 地址传递函数(其实不存在地址传递函数,指针会讲)

               普通函数 和 主函数(main函数)

                               一个程序必须有且只能有一个主函数,作为数据入口,不能有两个,不然数据不知道从哪进

                               主函数可以调用普通函数, 普通函数不能调用主函数,因为主函数是程序调用的出入口

                               普通函数可以相互调用

                               主函数是程序的入口,也是程序的出口

 

例子:

# include<stdio.h>

//判断一个数字是否是素数,判断真假用bool布尔只有两个值:truefalse来代替  0 1

//被调函数功能要单一,不要杂七杂八的,功能要分开写

//此函数只要判断没有处理

bool IsPrime(int val)//需要接收数据,对数据进行判断,因为这个函数是用来判断一个数是否是素数,必须定义一个形参,用形参来接收待判断的数字

{

//把main函数的拉来

int i;

    

    //尽量不要出现两处有输入数字的程序口

//printf("请输入数字判断素数:");

//scanf("%d", &val);

for(i=2; i<val; ++i)

{

if (val%i == 0)//i= val就意味着i<val不成立

//一旦能整除,说明它不是素数,只要有一个能整除就不是素数

break;//出现一个整除,直接终止for循环

//1、如果是因为break而终止for循环,i的值有没有可能是val,一旦break能执行说明i一定比val小,如果i不小于val,内部代码执行不了

//首先进入for循环,如果是素数,判断val%i是否为零。余数为零,则if后表达式为真,执行break,然后终止循环,转为判断i是否等于val,如等于写 说明val知道能被1和它本身除尽,为素数;余数不为零,则相反

}

if (i == val)

return true;  //此函数只需要判断val是否是素数就可以,其他功能分配给其他程序处理

//        printf("YES!\n"); //break会直接终止循环,要在外围设置printf

else

return false;

//        printf("NO!\n");

return 0;  //执行到return直接终止此处主函数

//return true;

//return false;

}

int main(void)

{

int m;

printf("请输入你要输入的数字判断是否是素数: ");

scanf("%d", &m);

if(IsPrime(m))//写入m,开始调用        IsPrime函数,会把m的值发送到  bool IsPrime(int val)  中的val,程序开始执行内部代码,要么返回truefalse

//然后if(IsPrime(m))里面的值:  IsPrime(m) 是 0 或 1

//现在调用isprime函数,各个val没有冲突,只能在各自主函数被使用

printf("YES!\n");

else

printf("NO!\n");

}

/*

要想知道5是不是素数,只需要把1到5中间的数:2,3,4,拿5依次相除,看能不能整除,只要有一个能整除就不是素数

  //此函数只要判断没有处理

 

  //bool IsPrime(int val)要放到main函数前面,放到main函数后面的话要加前置声明

 

  //所有被调函数要放到main函数前面,放后面麻烦

 

 

if(IsPrime(m))//写入m,开始调用        IsPrime函数,会把m的值发送到  bool IsPrime(int val)  中的val,程序开始执行内部代码,要么返回true或false;

//然后if(IsPrime(m))里面的值:  IsPrime(m) 是 0 或 1

*/

# include<stdio.h>

//void f(void)

//void f(int i, int j)

void f(int i)  //int i 这变量叫形参

{

return;

}

int g(int i)

{

return 10; //终止并返回一个值

}

int main(void)

{

//f(5);

int i;

i = g(5);//    凡是出现  ____()   前面是一长串字符,后面有括号---通常都是函数调用

printf("%d\n", g(5));

//printf("%d\n", f(5)); //被调函数的行首的void表示没有返回值,error C2664: 'printf' : cannot convert parameter 2 from 'void' to 'f(5)'

return 0;

}

注意的问题

常用的系统函数

专题:

       递归

                   

如何定义函数

注意的问题

             函数调用和函数定义的顺序

             如果函数的调用写在了函数定义的前面,则必须加函数前置声明

             函数前置声明的作用:

                                    1、告诉编译器即将可能出现若干个字母代表的是一个函数

                                    2、告诉编译器(软件)即将出现的若干个字母所代表的函数形参(变量)和返回值的具体情况

                                    3、函数声明后面一定要加一个分号,告诉程序它是一个语句

                                    4、对库函数的声明是通过 #include <库函数所在的文件的名字.h>来实现的

                                         比如printf () 函数的声明已经放到了 整个程序行首的 # include<stdio.h>-----系统的函数不需要声明

                                         stdio--- standard  i/o  标准输入输出

             形参和实参

                            个数相同  位置一一对应 数据类型必须相互兼容

                            一个函数的功能尽量独立,单一

                            对于一个初学者而言,多模仿牛人的代码,不是去自个想,而是去模仿牛人的代码

   【重点、难点】如何在软件开发中合理的设计函数来解决实际问题

                         一个函数的功能尽量独立,单一

                        多学习,多模仿牛人的代码

函数是C语言的基本单位,类是Java,C# ,C++的基本单位

常用的系统函数

               double aqrt(double x);

                        求X的平方根

               int abs(int x)

                         求x的绝对值--整数的绝对值

               double fabs(double x)

                         求x的绝对值--浮点型的绝对值

专题:

        递归

栈 : 是个杯子,只能从一个口入也只能从该口出,这就是栈

        所有能够实现先进后出--这种丛属结构--它都是栈

压栈:把它的东西放进去

出栈:把东西抛出去

变量的作用域和存储方式:

           按作用域分:

                        全局变量

                                在所有函数外部定义的变量叫全局变量

                                全局变量使用范围:从定义位置开始到整个程序结束

# include<stdio.h>

int k = 1000;

void f(int i)  //i是局部变量,它是形参,在函数内部定义的变量

{

int j = 20;

}

int main(void)

{

int i = 10;

return 0;

}

                        局部变量

                                在一个函数内部定义的变量或者函数的形参  都统称为局部变量

                                                              

                                                           void f(int i)  //i是局部变量,它是形参,在函数内部定义的变量

                                                              {

                                                    int j = 20;

                                                              }

                                         i和j 都属于局部变量

                         局部变量使用范围:只能在本函数内部使用

                  注意问题:

                         全局变量和局部变量命名冲突问题

                                    在一个函数内部如果定义的局部变量的名字和全局变量名一样时,局部变量会屏蔽全局变量

指针:【C语言的灵魂】

   指针:就是地址;    地址:我们内存单元的编号;    

   内存单元的编号:  

我们的内存条内部分多个小单元,一个单元有八位,存放8个0  和   8 个1

我们内存的编号不是以位来算的,是以字节算的; 不是一个0一个1一个编号;

而是8个零,8个1一个编号,一个字节一个编号,这个编号就是地址,就像一栋房子,每个有编号的房间只能存放8个1,8个零(一个字节)

所谓的指针就是地址 

           按变量的存储方式

                     静态变量

                     动态变量

                     寄存器变量(寄存器:CPU内部可以存储数据的硬件)

指针热身:

指针就是地址,地址就是指针(指针只是一个值,一个内存编号,不是变量)

地址就是内存单元的编号

指针变量是重复地址的变量(指针变量才可以存放数据)

指针和指针变量是两个不同的概念

但是要注意,通常我们叙述是会把指针变量简称位指针,实际它们含义并不一样

指针是 1000H, 指针变量是 p

# include<stdio.h>

int main(void)

{

//地址一般用十六进制表示

int *p;  //   声明;p:指针变量,指针是个修饰词,本质上还是一个变量(而是一个特殊变量,能够存放其他变量地址的变量)(普通变量只能存放一个值)\

             // int *p; 不表示定义了一个名字叫做 *p的变量

         // int *p; 应该这样理解: p是变量名,p变量的数据类型是 int *类型

         //         所谓 int * 类型   实际就是存放int变量地址的类型

int i = 3;

p = &i;  // i 和 p  是不同的变量,一个变量修改不会影响另一个变量

//      要背

    /*

    1、p保存了i的地址,因此p指向i;(指向)

2、p不是i,i也不是p,更准确的说, 修改 p的值不影响i的值,修改i的值也不会影响p 的值

3、如果一个指针变量指向了某个普通变量,则

         *指针变量  就完全等同于   普通变量

 

               例子:

       如果p 是个指针变量,并且 p 存放了普通变量 i 的地址

   则 p 指向了普通变量;

   *p  就完全等同于  i

   或者说:  在所有出现*p的地方都可以替换成 i

             在所有出现 i 的地方都可以替换成 *p

 

                   * p 就是以p的内容地址的变量

 

*/

printf("%d\n", &i);

 

printf("%d\n", p);

 

 

printf("%d\n", *p); //*p 就是 i

/*

 

    1703720

    1703720

    3

    Press any key to continue

 

*/

return 0;

}

指针:讲指针的目的第一个原因是动态内存分配,二是跨函数使用内存

           指针的重要性:

                表示一些复杂的数据结构

                快速的传递数据(请看程序di-16中的确定一个一维数组需要几个参数_3(一个数据发送到函数,用函数对这个数据进行处理,这时候用指针速度是非常快的)

                使函数返回一个以上的值

                能直接访问硬件

                能够方便的处理字符串(专题)

                是理解面向对象语言中引用的基础(讲Java的时候会讲)

                总计:指针是C语言的灵魂

         

          指针的定义

                   地址

                         内存单元的编号

                         从零开始的非负整数

                         范围:(CPU可以对内存条直接进行处理,越小的东西越快,大的东西成本低)

控制线:数据传递的方向由控制线控制的

数据线:数据线进行数据的传输(内存数据给CPU处理,写入内存条)

地址线:地址线要确定哪个单元,具体要对内存条哪个单元进行操作,由地址线控制的

                        

现在只考虑地址线

                   2^n线(每个单元就是8位,一个单元一条线)

                   字节:2^32 * 8

                   4G  32位操作系统最高支持4G内存的原因

          指针      (导致内存泄漏和野指针问题)

                    指针就是地址,地址就是指针

                    指针变量就是存放内存单元编号的变量,或者说指针变量就是存放指针的变量

                   

                     指针变量是重复地址的变量(指针变量才可以存放数据)

                     指针和指针变量是两个不同的概念

                    指针的本质就是一个操作受限的非负 整数(地址不能相加,房子的门牌号相加有什么意义,乘也不能,乘是加法的一种,编号不能相除)

                    指针可以相减(你的门牌号是5,他的门牌号是8,相减为3,你们隔着3个)

                    只可以相除(受限,因为非负整数可以加减乘除,而指针只能除

          指针的分类

          1、基本类型指针

# include<stdio.h>

int main(void)

{

//地址一般用十六进制表示

int *p;  //   声明;p:指针变量,指针是个修饰词,本质上还是一个变量(而是一个特殊变量,能够存放其他变量地址的变量)(普通变量只能存放一个值)\

             // int *p; 表示定义了一个名字叫做 *p的变量

         // int *p; 应该这样理解: p是变量名,p变量的数据类型是 int *类型

         //         所谓 int * 类型   实际就是存放int变量地址的类型

int i = 3;

p = &i;  // i 和 p  是不同的变量,一个变量修改不会影响另一个变量

//      要背

    /*

    1p保存了i的之地,因此p指向i;(指向)

2、p不是i,i也不是p,更准确的说, 修改 p的值不影响i的值,修改i的值也不会影响p 的值

3、如果一个指针变量指向了某个普通变量,则

         *指针变量  就完全等同于   普通变量

               例子:

       如果p 是个指针变量,并且 p 存放了普通变量 i 的地址

   则 p 指向了普通变量;

   *p  就完全等同于  i

   或者说:  在所有出现*p的地方都可以替换成 i

             在所有出现 i 的地方都可以替换成 *p

                   * p 就是以p的内容地址的变量

*/

printf("%d\n", &i);

printf("%d\n", p);

printf("%d\n", *p); //*p 就是 i

/*

    1703720

    1703720

    3

    Press any key to continue

*/

return 0;

}

 

 

# include<stdio.h>

int main(void)

{

int i = 5;

int *p;

int *q;    // *q 是垃圾值, *q 所代表的内存单元的控制权限并没有分配给本程序,没有初始化(q 没有指向)        

p = &i;

//*q = p;   //error 语法编译会出错

// *q 是垃圾值  ,*q 是整型,p是int *型

//*q = *p;  error , *q没有初始化

    p = q; //q是垃圾值,q 赋值给 p,p 也变成垃圾值

printf("%d\n",*q);        // q 的空间是属于本程序的,所以本程序可以读写 q 的内容,但是如果 q 内部是垃圾值,则本程序不能读写 *p 的内容

                          //因为 *q 所代表的内存单元的控制权限并没有分配给本程序 ,q 没有指向

return 0;

}

 只需要写一个free(p);  因为p,q,r都指向同一个动态内存地址空间,而一个空间只需释放一次

但是一个程序写的很大的时候,好多指针都指向同一个动态内存地址空间,如果你一次都不free,会导致内存泄漏

# include<stdio.h>

void huhuan_1(int , int);

void huhuan_2(int *, int *); // 形参不重要 ,声明的主要目的是告诉别人字符串的含义是什么,代表的是它的返回值和形参的类型

void huhuan_3(int *, int *);

 

void huhuan_3(int *p, int *q)

{

int t;   //如果要互换*p和*q的值,则t 必须定义成int ,不能定义成int *,否则语法出错

t = *p;  // p 是int * , *p 是 int ,是以 p的内容为地址的值,p 表示a 的地址,*p《=》a

*p = *q;

*q = t;

}

int main(void)

{

int a = 3;              // a, b地址一开始就已经定死的了

// 没有一门语言可以把静态变量的空间换地址

int b = 5;             //但是实参a,b 还存在,还是没有互换

int t;                 //只是改变了形参a,b的值,主函数的a,b没有改变

// a 和b 的指针互换了, a ,b 的值和哪个指针指向它无关, *p , *q 的指针互换了

huhuan_3(&a, &b);     //huhuan_2(*p,*q);    error,main函数没有定义 p , q   

printf("a = %d, b = %d\n", a , b);

return 0;

}

void huhuan_1(int a, int b)   //形参 a,b互换了,但是释放了,没有了

{

int t;

t = a;

a = b;

b = t;

}            //执行完后没有了a,b

//不能完成互换功能

void huhuan_2(int *p, int *q) //虽然*p,*q各自接收了 a,b的地址,只可惜,只改变了 p , q的值 ,没改变*p , *q 的值 , q ,p 和a ,b 是不同的值,改变 q ,p ,不会影响 a,b 的值  

//(地址还是那个地址,只是 q,p的内容互换了,就是 p 和 q 的指向地址互换了)

// q , p 是 int *类型  ,a ,b 是int 类型  ,void 没有返回值

//  a, b, p, q 是不同的变量,互不影响

{

int *t;  //想要互换 p, q的值,要用 int * 类型

t = p;   // t 是指针变量,地址变量,门牌号变量

p = q;

q = t;  

//互换 p , q 地址, a , b 没变

    // 只要是变量就有地址

}

附注:

       *的含义

                1、乘法

                2、定义指针变量

                      int *p;

                      //定义了一个名字叫p 的变量, int *表示 p 只能存放int 变量的地址

                3、指针运算符

                            该运算符放在已经定义好的指针变量的前面

                            如果p 是一个已经定义好的指针变量

                            *p 表示 p的内容为地址的变量(p指向 &I ,则 *pi的地址的变量 = *p = i

 

 

# include <stdio.h>

void swap_3(int * p, int * q) //形参名字是p和q,接收实参数据的是p和q,而不是*p和*q

{

int t;

t = *p; *p = *q; *q = t;

} // 形参和实参永远不可能是同一个变量,而且形参变量的空间在函数调用完后一定没有了,被释放了

  //终止之后,*p 和 *q 的值已经没有了,但是 a ,b 的值已经被改写了,swap_3内部执行过程中* p 和 * q指向的变量互换了

int main(void)

{

int a = 3;

int b = 5;

swap_3(&a, &b);   // 如果要把a 发送给一个变量p,一定要先为这个变量p 分配空间,分配一个空闲的空间,所以p和a的地址空间一定不是同一个地方

printf("a = %d, b = %d\n", a, b);

return 0;

}

void swap_1(int i, int j)

{

int t;

t = i; i = j; j = t;

}

//使用发送地址

void swap_2(int * p, int * q) //形参名字是p和q,接收实参数据的是p和q,而不是*p和*q

{

int * t;

t = p; p = q; q = t;

}

 

 

如何通过被调函数改主调函数普通变量的值

          1、实参必须为该普通变量的地址

          2、形参必须为指针变量

          3、在被调函数中通过

                   * 形参名 = ……

               的方式就可以修改主调函数相关变量的值

          2、指针和数组(关系)(链表)

                指针和一维数组  (数组是连续的,下标,下标和指针联系在一起的)

                               一维 数组名a

                                       一维数组名是个指针常量

                                       a:它存放的是一维数组第一个元素的地址

例子:

int a[5];   //a 是数组名 ,5是数组元素的个数,元素就是变量  a[0] -- a[4]

//int a[3][4]; // 3行4列 ,a[0][0] 是第一个元素 a[i][j] 第i+1 行 j+1列

int b[5];

 

//        a = b;  // error , a是个常量 ,常量变了就不是常量了

 

printf("%#X\n", &a[0]);   //   十六进制输出   %#X  ,&a[0]  a[0]第一个元素的地址

printf("%#X\n ", a);      //  数组名a 是第一个元素的地址

 

/*

  输出结果:

  --------------------------------------------

      0X19FF1C

      0X19FF1C

      Press any key to continue

  --------------------------------------------

  结论:

  a   等同于   &a[0]

*/

                     

                              下标和指针的关系

                                       如果p 是个指针变量,则

                                       p     永远等价于  &p[0]

                                       p[i]  永远等价于 *(p+i)

# include<stdio.h>

void f(int *pArr, int len)

{

pArr[3] = 88;         //p[i]  永远等价于 *(p+i)  ,p[i] 是变量

}

int main(void)

{

int a[6] = {1, 2, 3, 4, 5, 6};

printf("%d\n",a[3]);

f(a, 6);  // f(a,10000);  下标越界

printf("%d\n",a[3]); //a[3] == *(a+3)

// 为什么a[3] 是第四个元素?  a[3] 等价于 *(a+3), a+3 是第四个元素的地址 ,*(a+3)代表的是第四个元素,所以 a[3] 是第四个元素

return 0;

}

                             确定一个一维数组需要几个几个参数

                             【如果一个函数要处理一个一维数组,则需要接收该函数数组的哪些信息】

                                        需要两个参数:

                                                数组第一个元素的地址 a  (指针类型 int *)   a a[0]的地址  a == &a[0]

                                                 a = &a[2]; //error ,a 是个指针,存放a[0]地址,是个常量,不可能改变

                                                数组的长度  len  (int 类型)

//此程序体现了指针如何快速的传输数据(通过发送变量地址解决)

# include<stdio.h>

void f(int *pArr, int len )  // 对 pArr[i]的操作 就相当于 在主函数中 对 b[i] 操作 ,一模一样的

 

// 就可以通过f 函数修改 主函数 int b[6] 六个变量的值,修改主函数所有变量!

//而且通过发送它的地址和长度,在 f 函数操作,感觉就像在main 函数对 b 数组进行操作

// b数组发送给pArr, pArr数组就是b数组的一份拷贝(副本)

{

int i;

for(i=0; i<len; ++i)

{

printf("%d  ", pArr[i]);  //  *(pArr + i)等价于 pArr[i]  也等价于 b[i]  也等价于 *(b + i)  下标转换成指针

}

printf("\n");

}

int main(void)

{

int b[6] = {-1, -2, -3, 4, 5, -6};

f(b, 6);

return 0;

}

                            

                               指针变量的运算

                                      指针变量不能相加  不能相乘  也不能相除

                                      如果两个指针变量指向的是同一块连续空间中的不同存储单元

                                      则这两个指针变量才可以相减(比如你有个门牌号一个西安某个小区门牌号,一个是上海某个小区门牌号,相减没有意义,要同一个小区)

                               一个指针变量到底占几个字节

                                          预备知识:

                                                 sizeof(数据类型)

                                                 功能:返回值就是数据类型所占的字节数

                                                 例子: sizeof(int ) = 4  sizeof(char ) = 1

                                                            sizeof(double) = 8

                                      sizeof(变量名)

                                      功能:返回值是该变量所占的字节数

                                      假设 p 指向char 类型变量(1个字节)

                                      假设 q 指针int 类型变量(4个字节)

                                      假设 r  指向double 类型变量(8个字节)

                                       p  q  r  本身所占的字节数是否是一样?

                                              答案: p  q  r  本身所占的字节数是一样的(4个字节)

                                              (char int double ,它们在32个状态表示形式不同,char类型就只有一个字节,只能指向一个,

                                                int类型4个,但定义的q只指向4个字节的首个,double8个字节,而r只指向首个)

                                               而不同变量类型的首字节都是由32根地址总线的不同状态组成的(4*8 = 32 位

                                            

                                             

                                                                                          // 房子,如果房子就只有两栋,编号就很小

                                                                                          // 假如房子很多很多,10000个房子,第一个房子的大小它本身的编号大小不是一个概念

                                                                                          // 假设有一万个房子 , 某一个房子本身可以很小, 但因为房子本身比较多,编号就很大

                                                

                                     也就是  p q r 的(首)字节大小(地址编号)是由计算机本身所分配的地址大小确定的(32位)

                                     p q r 本身数据类型的实际大小无关

                                   计算机就分配了p q r 4个字节的地址给你,你用多少是你的事情,门牌号是几(32

                                   一字节:8bit:  0000 0000

                                      总结:

                                                一个指针变量,无论它指向的变量占几个字节

                                                该指针变量本身只占四个字节

                                               一个变量的地址使用该变量首字节的地址来表示

                                               

                                                                   因为指针变量本身保存的是一个地址,而这个地址的位数最多也就32位(32位的机子),

                                                所以4个字节乘以8位,就是32位了,正好能够满足存放一个最大地址的需要。

                                                 一个变量的地址使用了该变量首字节的地址来表示的。

                                                 指针变量是通过数据类型和首字节的地址拿出的所有数据 *p

                                                来自 <小蚂蚁学习C语言(19)——C语言指针——指针变量的运算和占用几个字节_weixin_34265814的博客-CSDN博客>

# include<stdio.h>

int main(void)

{

char ch = 'A';

int i = 99;

double x = 66.6;

char * p = &ch;

int *q = &i;

double * r = &x;   

    // 指针就是地址,地址就是指针

    //p 也是个指针变量,有空间,需要4个字节保存,地址就是内存单元的编号,有32根地址总线来组合(一个指针变量无论它指向的变量占几个字节,它本身都只占4个字节)

printf("%d %d %d\n", sizeof(p), sizeof(q), sizeof(r)); // x 占8个字节,一个字节算一个单元,一个字节一个编号(8个0或1一个编号,一个字节占8位)

// x 有八个字节, 第一个编号当作了x 的编号,char指向第一个字节(只有一个字节), int 指向第一个字节,把第一个编号当作的标志

// 只保存各自类型的第一个字节的编号(地址)

//  p  q  r 都指向的是 各自的第一个地址,但它们各自总体长度是几,靠的是它们各自定义的char int double 决定的

// 一个变量地址只用第一个字节地址表示

// 虽然它们三个指向第一个字节地址,但他们本身指针变量类型就可以确定出它到底指向的变量占几个字节

// p q r 都只占4个字节,它们都存放第一个字节地址,而它们输出长度又是4,就意味着说我们的第一个字节地址要用4个字节表示

// p q r 中只存放了一个字节的地址,但是 p q r 却占 4 个 字节? -- 说明地址占4个字节,或者这个编号,虽然 p 是第一个字节地址,但是第一个字节地址它是个编号,编号本身需要4个字节

// 编号本身需要4个字节去保存

// 房子,如果房子就只有两栋,编号就很小

// 假如房子很长很长,10000个房子,第一个房子的大小和它本身的编号大小不是一个概念

// 假设有一万个房子 , 某一个房子本身可以很小, 但因为房子本身比较多,编号就很大

// 虽然 p q r 只占一个字节,但是字节太多了,编号就比较大,大的编号刚好用 4 个 字节去表示

// 那为啥是4个字节呢?

//CPU 里面控制内存有 32 根线 , 一根线有两个状态(0、1),一共 2^ 32个状态,不同的状态可以确定一个单元(一个字节算一个单元)

// 因为地址总线是32 位,所以编号有 4G 个编号,第一个编号和第二个编号都需要 32 根线,只不过是用了 32 根线不同的状态去表示

// 比如第一根线,编号可能是 0 的地方编号是 0000 0000 0000 0000 0000 0000 0000 0000

// 第二个地址(第二根线),编号可能是编号是 1111 1111 1111 1111 1111 1111 1111 1111

// 32 根线可以确定 4 G 个不同个状态

// 无论是第一个状态还是最后一个状态,或者说无论是第一个编号还是最后一个编号,它都要4 个 字节去保存,最终 p q r 里面都占 4 个字节(4个字节就是 32位, 4*8 = 32)

// 32 根线就是32个比特 也就是4个字节

// 我们内存中的第一个编号肯定从零开始的,最后一个编号肯定是很大了

//无论是第一个编号还是最后一个编号,它们都是用32根线来表示的,它们都需要在内存里面用4个字节去保存

//第一个编号只不过是32根线加上零: 0000 0000 0000 0000 0000 0000 0000 0000

// 也就是这个地址由32个二进制组成,一个字节存放8个二进制位所以4个字节

// 一根线代表1bit,32根线需要32bit,1字节=8bit

return 0;

}

                指针和二维数组(最难)

          3、指针和函数

          4、指针和结构体

          5、多级指针

专题:  (难度大)  

            动态内存分配(讲指针的目的第一个原因)

                               传统数组的缺点:

                                   1、数组长度必须事先制定,且只能是常整数,不能是变量

                                        例子:

                                                int a[5];  //长度定死的  ,true

                                                int len = 5; int a[len]; // error

                                   2、(坐车不能闲着,要有发现美的眼镜)

                                        传统形式定义的数组,该数组的内存程序员无法手动释放(系统自动释放)

                                         数组一旦定义,系统为该数组分配的空间,就会一直存在,除非该数组所在的函数终止

                                         数组一旦定义,系统为该数组分配的存储空间就会一直存在,

                                         除非数组所在的函数运行完毕结束

                                         在一个函数运行期间,系统为该函数中所分配的存储空间会一直存在,直到该函数运行完毕时,数组的空间才会释放

void f()

{

int a[5] = {1,2,3,4,5}; 

// 20 个字节的存储空间程序员无法手动编程释放它,它只能在本函数运行完毕时,由系统自动释放,f函数 什么时候完了(f终止的时候,f不运行完毕,20个字节永远存在),20个字节存储空间就释放

}

                                 3 数组的长度一旦定义,其长度就不能再更改

                                       数组的长度不能再函数运行的过程中动态的扩充或缩小

                                 4、A函数定义的数组,再A函数运行期间可以被其他函数使用,

                                      但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用

                                      传统方式定义的数组( int a[5];)不能跨函数使用(静态)

                               为什么需要动态分配内存

                                       动态数组很好的解决了传统数组的这4个缺陷

                                       传统数组也叫静态数组

                               动态内存分配举例_ 动态数组的构造(难度更大)

                                 假设 p 刚好指向某个存储地址(一横代表一个字节地址)

                                 【注意】这里说的是无法确定指针变量所指向第一个的地址类型

        

# include<stdio.h>

//先讲最基本的语法,最后是完整的例子

/*

    2021/5/30   9:30

malloc 是memory(内存)  allocate(分配)的缩写(请求分配内存)

*/

# include<malloc.h> //malloc在malloc.h 文件中放着

int main(void)

{

int i = 5; // 分配了4个字节 静态分配

int * p = (int *)malloc(4);// p 指向4个字节,但p本质上只保存了第一个字节地址,4个字节只用首地址表示,int *类型已经让我们知道是4个字节为一个变量单元了

   /*

         1、要使用malloc函数,必须添加malloc.h这个头文件

 2、malloc函数只有一个形参,并且是形参是整型

 (系统定义的时候,有几个形参)(一个,实参只有一个,形参就只有一个),如果实参一个形参两个,程序会报错。

 3、4表示请求系统为本程序分配4个字节,malloc(必须是整数),字节不可能是3个半

 4、malloc函数只能返回第一个字节的地址,那第一个字节的地址有没有实际意义

 5、malloc函数分配了4个字节,而且只能返回第一个字节地址给 p

 也就是系统通过 p 调用 malloc 函数时,通过 p 的值来确定malloc 函数的地址,而malloc函数默认返回第一个字节地址

 假设 p 刚好指向某个存储地址(一横代表一个字节地址),因为malloc 函数刚好返回这一字节地址(连续分配空间的4个字节的第一个字节地址(首地址))

 那这时候,    p 到底占几个字节, p 指向的变量到底占几个字节?(你不知道在4个字节里头,从第一个字节开始怎么去分配这4个字节,是一个个呢,还是2个2个,还是直接4个就当整体用了)

 第一个字节地址本身不能确定它指向的变量到底占几个字节(不能确定它的大小)

                       (int *)malloc(4);把第一字节地址(这个地址本身无实际意义(malloc函数返回的第一个字节类型是void),不加强制类型转换,地址的位数不能确定

 因为你连它是什么类型都不知道,这时候要强制转换成有实际意义的地址,可以让人们使用,看的懂)强制转换成  一个 整型的地址(int *)

 (char*)malloc(100);  // 返回100个字节,一个字节一个变量

 (int*)malloc(100);   //  返回值还是一样的,还是第一个字节地址,但是它知道第一个字节地址代表是整型变量的地址,

 mlloc函数就知道虽然只有第一个字节地址但是它知道按4个字节,4个字节发放分配,最后整体100个字节是25个变量

         malloc函数虽然返回了第一个字节的地址,但它表示的不是第一个字节的地址,而是整型变量的地址,整型变量的地址肯定是4个,4个划分的

         【注意】这里说的是无法确定指针变量所指向第一个字节的地址类型

 

   */

return 0;

}

      

# include<stdio.h>

//先讲最基本的语法,最后是完整的例子

/*

    2021/5/30   9:30

malloc 是memory(内存)  allocate(分配)的缩写(请求分配内存)

*/

# include<malloc.h> //malloc在malloc.h 文件中放着

int main(void)

{

int i = 5;                   // 14行

// 分配了4个字节 静态分配

int * p = (int *)malloc(4);            // 17行 

// p 指向4个字节,但p本质上只保存了第一个字节地址,4个字节只用首地址表示,int *类型已经让我们知道是4个字节为一个变量单元了

// p本身身为指针变量只能指向第一个字节地址,但是 p 前面定义了数据类型 int ,达到的效果是 p 可以指向4个

  

       //p 本身的4个字节内存和malloc分配的4个内存是不是一样的内存(动态?静态)

       //不是  p 是 静态(数据类型+变量名) ,malloc (p 是栈里面的, malloc是堆里面的)

   /*

         1、要使用malloc函数,必须添加malloc.h这个头文件

 2、malloc函数只有一个形参,并且是形参是整型

 (系统定义的时候,有几个形参)(一个,实参只有一个,形参就只有一个),如果实参一个形参两个,程序会报错。

 3、4表示请求系统为本程序分配4个字节,malloc(必须是整数),字节不可能是3个半

 4、malloc函数只能返回第一个字节的地址,那第一个字节的地址有没有实际意义-- 没有,除非定义 数据类型

 5、malloc函数分配了4个字节,而且只能返回第一个字节地址给 p

 也就是系统通过 p 调用 malloc 函数时,通过 p 的值来确定malloc 函数的地址,而malloc函数默认返回第一个字节地址

 假设 p 刚好指向某个存储地址(一横代表一个字节地址),因为malloc 函数刚好返回这一字节地址 (连续分配空间的4个字节的第一个字节地址(首地址))

 那这时候,    p 到底占几个字节, p 指向的变量到底占几个字节?(你不知道在4个字节里头,从第一个字节开始怎么去分配这4个字节,是一个个呢,还是2个2个,还是直接4个就当整体用了)

 第一个字节地址本身不能确定它指向的变量到底占几个字节(不能确定它的大小)

                      (int *)malloc(4);把第一字节地址(这个地址本身无实际意义(malloc函数返回的第一个字节类型是void),不加强制类型转换,地址的位数不能确定

 因为你连它是什么类型都不知道,这时候要强制转换成有实际意义的地址,可以让人们使用,看的懂)强制转换成  一个 整型的地址(int *)

 (char*)malloc(100);  // 返回100个字节,一个字节一个变量

 (int*)malloc(100);   //  返回值还是一样的,还是第一个字节地址,但是它知道第一个字节地址代表是整型变量的地址,

 mlloc函数就知道虽然只有第一个字节地址但是它知道按4个字节,4个字节发放分配,最后整体100个字节是25个变量

         malloc函数虽然返回了第一个字节的地址,但它表示的不是第一个字节的地址,而是整型变量字节的地址,整型变量的地址肯定是4个,4个字节划分的

         【注意】这里说的是如果(   )malloc前面不定义数据类型,就无法确定指针变量所指向第一个字节的地址类型

         最终分配几个字节:

   p 也是个变量,有空间,需要4个字节保存,地址就是内存单元的编号,有32根地址总线来组合

(一个指针变量无论它指向的变量占几个字节,它本身都只占4个字节)

              17行分配了8个字节, p 变量占4个字节,  p 所指向的内存也占4个字节(malloc所分配的)

        6、 p 本身所占的内存(字节)是静态分配的,p 所指向的内存是动态分配的

 

   */

*p = 5;

// *p 是动态分配的 ,* p 表示的是 malloc所使用的 4个字节内存

// 代表的就是一个int 变量,只不过 *p 这个整型变量的内存分配方式和  14行 的 i 变量的分配方式不同

free(p);  // 终止 动态内存

// free(p); 表示把 p 所指向的内存(字节)给释放掉 ,p本身是静态的,指向地址字节是动态的

//本来这4个字节属于当前 叫malloc 的程序使用,所谓分配,就是4个字节的使用权限给malloc了;而释放就是4个字节内存不能再用,不能写和读

 

//p本身的内存是静态的,不能由程序员手动释放,p 本身的内存(所占的字节)只能再 p 变量所占的函数运行终止是由系统自动释放

printf("同志们好!\n");

return 0;

}

                       

    

                              malloc函数的用法_2          

# include<stdio.h>

# include<malloc.h>

void f(int *q)  // p q 指向同一地址空间

{

// * p = 200;  f()里面就没有 p 变量, p 在main函数定义的就只能在main函数使用 ,f 不能使用

//q 是 p 的一份拷贝, q 和 p 的内容是一样的 , 而 p 中存放的是 4 个字节的 地址

//那 q 中也存放了这 4 个字节的地址 ,q 指向这 4 个字节的变量,那 * q 就代表了这4个字节,那我们就可以把200赋值给这 4 个字节

* q = 200;

free(q); // 本语句必须注释掉,否则会导致第23行代码出错

 // 把 q 所指向的内存释放掉 ,这 4 个字节释放掉了,使用权没了

 

 // p 里面 4个字节想存放什么都可以, p 变量还是我的, free(q);只是 把 q 指向的内存空间释放掉了(* p 的内存释放了,访问权限没了)

}

int main(void)

{

int * p = (int *)malloc(sizeof(int)); //sizeof(int)返回值是int所占的字节数

* p = 10;

printf("%d\n", * p); // 10

//f(p); p 是 int * 类型

f(p);

printf("%d\n", * p); // 第23行

// 现在想通过 f()函数 把 * p 变 200

return 0;

}

                               静态内存和动态内存的比较

动态内存和静态内存的比较

                静态内存是由系统自动分配,由系统自动释放

                静态内存是在栈分配的(栈就是个杯子)

f()

{

A;

g();//当f()函数调用g()的时候,会把g()下面的语句B;的地址发送到g()函数,让g保持,紧接着为g函数的a,k分配存储空间,在栈里面去分配的

B;

}

g(int i)

{

int a[5];

int k;

c;

}

静态在栈

静态的存储空间在栈里面去分配的 -- 压栈、出栈

动态malloc在堆

                 动态内存是由程序员手动分配的,手动释放

                 动态内存是在堆分配的(堆是以排序来分配的)

                               静态内存:

# include<stdio.h>

# include<malloc.h>

int main(void)

{

int a[5]; // 只有main函数终止的时候, a[5]数组的使用空间才会被释放

// 如果int 占4个字节的话,则本数组总共包含20个字节,每 4 个字节被当做了一个 int 变量来使用

int len;

int * pArr; // pArr存放的是系统分配的连续内存空间的第一个字节地址,又由于 pArr本身是 int *类型,所以pArr指向的是前4个字节

// * pArr 就代表了 前4个字节的整型变量

// pArr 指向的是 一维数组元素,每个元素占4个字节

// * (pArr + 1) 就会指向 当前 pArr所占的字节的后4个字节,依次同理(记住这是连续的内存空间)

int i ;

// 前面讲过 , 所有的指针变量下标都可以转换成指针(指针就是地址,地址就是指针,名称不同) pArr[0] = * pArr;    pArr[2] = * (pArr + 2)

// 动态的构造一维数组

printf("请输入你要存放的元素的个数:");  // 我希望程序运行当中,由用户来手动输入,来创建多长的数组

scanf("%d", &len);

pArr = (int *)malloc(4 * len);   // 这行代码 就类似于  写了   int pArr[len]; 只不过这是动态分配的  -------一维数组已经动态构造好了,构造就是 造了、搞 的意思

//本行动态的构造了一个一维数组,该一维数组的长度是len (int类型变量占 4个字节)

//该数组的数组名是pArr,该数组的每个元素类型是int类型(因为pArr返回的第一个字节的地址当成了整型的地址 (int *)malloc,按整型来划分的)  类似于  int pArr[len];

//这行代码执行完后导致的结果是,我们的操作系统给我们找到了一个20个字节的空闲空间,分配给我们这个当前的程序,并且pArr指向的是前4个字节

// 对一维数组进行操作

// 对动态一维数组进行赋值

printf("注意空格隔开,请分别输入5个你要赋的值:");

for(i=0; i<len; ++i)

{

scanf("%d",&pArr[i]); 

}

// 对一维数组进行输出

printf("一维数组的内容是:\n ");//加个提示符

for(i=0; i<len; ++i)

printf("%d\n",pArr[i]);

free(pArr); //释放掉动态分配的数组, 静态数组不能手动释放

return 0;

}

输出结果:

                               跨函数使用内存的问题(单独拉出来的知识)

 

结构体

                  为什么需要结构体

                                  为了便是一些复杂的事物,而普通的基本数据类型无法满足实际需求

                  怎么加结构体

                                  把一些基本数据类型组合在一起形成的一个新的复合数据类型,这个叫结构体

                  如何定义一个结构体(三种方式)

                  只需掌握第一种方式(不推荐后两种)

# include<stdio.h>

//定义结构体的第一种方式         这只是定义了一个新的数据类型,并没有定义变量

struct Student

{

int age;

float score;

char sex;

};

//定义结构体的第二种方式

struct Student2

{

int age;

float score;

char sex;

} st2;   // 定义结构体的同时,定义变量名,意味着只能定义一次,第二次再使用的话就会出问题

//定义结构体的第三种方式

struct

{

int age;

float score;

char sex;

} st3;       //第三钟连变量是什么类型都不知道

int main(void)

{

struct Student st = {80,66.6,'F'};

return 0;

}

                    怎么去使用结构体变量

                                  赋值和初始化

                                               定义的同时可以整体赋初值(初始值)

                                               如果定义完之后,则只能单个的赋初值

                                   

                                  如何去除结构体变量中的每一个成员

                                               1、结构体变量名.成员名

                                               2、指针变量名->成员名         (第二种方式更常用)

                                                             指针变量名 -> 成员名 在计算机内部会被转化成 *指针变量名).成员名的方式去执行

                                                             所以说这两种方式是等价的

struct Student

{

int age;

float score;

char sex;

};

int main(void)

{

struct Student st = {80,66.6,'F'}; // 第一个是定义的同时去赋值,初始化  定义的同时赋初始值

struct Student *pst = &st;  // &st 不能够改成 st

// pst变成一个指针了

//写* 表示 pst 能存放前面 这个struct Student类型的地址  ,把struct Student  当作是 int

pst->age = 88; // 第二种方式

st.score = 66.6f; //第一种方式   f 浮点型 

// 66.6在C语言中默认是double类型,如果希望一个实数是float类型,则必须在 66.6 后面加 f 或 F ,因此 66.6 是double,66.6f或 66.6F 是float

printf("%d %f\n", st.age, pst -> score);

//上来就直接编译,不管程序报不报错

return 0;

}

              pst->age 在计算机内会被转化成  *pst.age, 没有为什么,这就是 ->的含义,这是一种硬性规定

              所以 pst -> age 等价于 *pst.age 也等价于 st.age  

             很重要,讲链表的时候要用到          通常只使用 pst -> age

             我们之所以知道pst -> age 等价于 st.age 是因为 pst -> age 是被转化成了(*pst.age 来执行的

            

             pst -> age的含义:(要背会)

             pst所指向的那个结构体变量中的age 这个成员

             pst -> age   只是代表的是 struct Student 中的 age 这个小成员        

                                  结构体变量的运算

                                  结构体变量和结构体变量指针作为函数参数传递的问题

                                                    推荐使用结构体指针变量作为函数参数来传递

                                  结构体变量的运算

                                                     结构体变量不能相加,不能相减,也不能相互乘除

                                                      但结构体变量可以相互赋值

                                                      例子:

                                                         

struct Student

{

int age;

char sex;

char name[100];

}; //分号不能省

Struct Student st1, st2;

St1+st2, st1*st2,  st1/st2 ;  都是错误的

但;

St1 = st2  或者  st2 = st1 都是对的

       

                                  举例

                                         动态构造存放学生信息的结构体数组

                                         要讲个排序的知识

                                         冒泡排序:大的和小的,一个个都往上

 

举例:

# include<stdio.h>

void sort(int * a, int len)

{

// 如何去排序

// 升序排,最后一个数据是最大值 ,第一个和第二个比,哪个大就哪个放后面,变成前两个数据的最大值,第二个和第三个比,哪个大哪个就放后面,变成前三个数据最大值......

//第一次要找到最大值要找几次? 1和2,2和3,3和4,4和5,5和6,一共5次

int i, j, t;

// for 循环表示整体表示要比较几次?

for(i=0; i<len-1; ++i)        //外层进行 5 次

{

//要进行某一次的比较了!

for(j=0; j<len-1; ++j)    // 内层 进行 5 次,外层每进行一次,内部就进行 一个数据对比所有数据的大小比较,比较完10后,2就会排在第一个,外层又触发1次循环,进行比较,依次知道完成所有比较

{

//某个数字和某个数字挨个去比较!

if(a[j] > a[j+1])

{

t = a[j];

a[j] = a[j+1];

a[j+1] = t;

}

}

}

}  // 漏掉了一个 ( } )

int main(void )

{

int i = 0;

    int a[6] = {10, 2, 8, -8, 11, 0};//排序和查找哪个重要,  排序!  排好了,查更简单,让数据更加有效

//要排序就要调用函数

sort(a,6);  // 排序就要把数据发过去, 首地址就能找到第一个元素,个数就能找到数据长度

// 调用完之后就可以输出

 for(i=0; i<6; ++i)

 {

 printf("%d ", a[i]);

 }

 // 输出完换行

 printf("\n");

 return 0;

}

 

                                  链表:(要通过链表知道什么是算法)

                                          

                                          

                                

进制:

             1、什么是n进制

                       逢十进一

             2、把r进制转成十进制

             3、十进制转成r进制

             4、不同进制所代表的数值之间的关系

               十进制的3981转化为 十六进制是  F8D

               十进制的3981和十六进制的F8D所代表的本质上都是同一个数字

结构体会影响到后面两门课的学习:一是数据结构;而是面向对象

 

复习:

          它是面向对象的链接

 

          指针的优点:

                                                  

        

                 

  • 快速的传递数据,
  • 耗用内存小
  • 执行速度快
  • 在多层循环中,break只能终止距离它最近的循环
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值