个人C语言学习笔记

2018-01-15

0.计算机的思考方式:枚举,小范围内的枚举,二分法。

 

1.double的scanf("%lf",&...) ,print(f%,...)是没有问题的;

 

2.count++ 是 count原来的值;

 

3.scanf("%d",&x)

  printf("%x",x)   此时的 %x 表示16进制,且字符只能是x字符;

 

4.什么是好的代码?  答:足够傻的代码。

 

5.所谓的else if是当年被屏幕宽度限制而所做的更改;“单一出口”

 

6.尊重warning,力争解决每一个warning。

 

7.if()中条件:零或非零。即:bool条件中只有零或非零。(非零表示正确)

 

8.风格三观。。。。。。每个企业都有自己的风格,服从企业风格。

 

9.计算机描述的步骤,而不是关系。

 

10.do while...语句是考虑了特殊情况,如:变量等于零。

 

11.for(int i = 2; i <= x; i++) //只有c99的编译器才支持for循环中的变量声明定义;

 

12.for(; i <= x; ){ i++;}  等同于 while(条件){}

 

//******************** 第六周 数据类型  *******************************

 

13.对于-a<10进制数>,其补码就是0-a,实际是2^n - a,n是这种类型的位数(溢出的零)。

 

14.unsigned(纯二进制的移位) ,255U / 255u

 

15.非unsigned的负一,就是unsigned最大值;例如:printf("int的最大值:%u  最小值:%d", -1 , -1);

 

16.整数的运算是准确的,浮点不一定准确。例如:

   ① f1==f2可能失败;但,当fabs(f1-f2)<f的精度时,f1==f2;

   ② 浮点也不能作为switch-case的条件跳转,只因它不够准确。

 

17.优先级:!> && > ||  ,!是单目运算符。例:!age<20  永远为真。

 

18.代码复制是程序质量不良的表现。例:维护不便;

 

19.无函数体(函数原型)就是声明<同时,声明‘可以’不需要写明参数名>,有,就是定义。(Ps:Java中不需要声明)

 

20.数组中的个数是定值,c99除外,它可以是变量。   Java中不可以。

 

21.我的编译器不是c99,int arr[10] = {[1]= 1,2, [5]=3}; //c中的数组的初始化 .

 

22.有没有读过7、80年代的计算机教科书,是看你有没有在数组定义时多留出一个逗号(‘,’),

 

23.计算机存储变量地址是按stack自顶向下(C语言的内存模型),即:由大到小;→

   又:printf("%p %p %p", &a, a, &a[0])数组a[]得到:&a == &a[0]( 当,求sizeof所占字节时,!= a),从而推出:数组数据存储是按倒序存储。即:arr[i-1]、arr[i-2]...arr[0]。

 

24.i==*p, &i==p==&*p; 分别对其%d和%p输出,一共可以得到四组数据;

  ①32位:后者的%d和%p一样,

  ②邻地址单位差一个int;

  !!!③与变量i不同的是:*p在左边时他是:左值,表达式计算的结果;原因:*是单目运算符,用于取值。类似的还有数组中的[];

 

25.金矿,传送门,&传送门==地图

 

26.数组变量和指针的关系

         老师说数组变量可以被看作是const的指针变量,到底是“可以被看作”,还是“就是”指针呢?

         用程序证据(而不是搜索教科书)来说明你的观点。

         (提示:如果对const指针的所有的操作都可以对数组变量做,而且结果一致,就说明数组变量就是指针;如果有某个操作不能做,或者结果不一致,就说明不是指针)

   ①初始化:数组初始化:实际值; const指针:地址;

   ②sizeof:前者:是计算整个数组长度;  后者:一个指针大小(它的大小取决系统位数);

/*

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

         int const* p = a;     //  //   p = a;  × 因为const必须要初始化;

         int  const * j;

         printf("%d\n", sizeof(int));         //判断数据类型

         printf("%d\n", sizeof(p+1));      //判断数据类型

          

         printf("%d\n", sizeof(&a+2));    //判断数据类型

         printf("%d\n", sizeof(a));   //数组长度

         printf("%d\n", sizeof(&a[0]));   //**数据类型

        

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

        printf("%p\n", a+1);

         printf("%p\n", &a); a指的是一个数组元素的地址,就相当于&a[0],而&a是指整个数组的地址

         printf("%p\n", &a+1);      //两者地址差==整个数组长度      

         从而得出一个性质:在f(int arr[])中只需一个arr指针就可计算出该数组的长度;例:利用&a+1 - &a = 整个数组长度;  

         但是:    

         f(&a);    // 不能把整个数组的地址都传过去; (int*[sizeof(arr)] not convert to int*)   

        

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

         printf("%p\n", &p+1);    //两者地址差为:2

                                   

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

         printf("%p\n", &a[0]);

*/

 

27.0~24    32       

   25~40   48

   41~56   64   推出:它以16的倍数递增;又:32-24=8,得:指针存储变量需8个位;

    

28.用指针还是数组表示字符串?

                  (1)构造字符串用数组;

                  (2)处理字符串用指针;

      ①数组:这个字符串就在这里:

           本地变量内存会自动回收;

      ②指针:不知道字符串在哪儿;

         作为参数;

           动态内存分配;

 

29.结构与数组:

         ① 数组是结构的特殊情况

         ② 我觉得结构更倾向于自然的抽象,类似于面相对象的类,数组就规矩多了,

       ③ 结构变量名是普通的变量名,而数组名是指针常量;

         ④ 数组是相同类型的数据组成的在内存上连续分布的, 而结构体内数据类型不一定相同,

         ⑤ 这两者共同实现了对数据的集成,模块化,结构化

 

30.#include <stdio.h>

#include <stdbool.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

 

;//声明预留

struct test fun(struct test fun1);

void printfmystruct(const char * p, const struct test * structname);

 

;//结构预留

struct test{

    int arr[10];

};

 

//突发奇想:数组的值能否利用结构进出函数体,能否整体赋值

//已知不能直接用数组名将数组的值传递进函数体,现试验利用结构包装数组能否实现数组值的传递,也不能进行数组的整体赋值

//试验成功:数组的值能利用结构包装在函数中正确赋值,其中数组也能够整体赋值

 

int main()

{

    struct test main1 = {{0,1,2,3,4,5,6,7,8,9}}, main2;

     

    printfmystruct("main1", &main1);

    

    //包含数组的结构体函数间赋值传递

    main2 = fun(main1);

     

    printfmystruct("main2", &main2);

     

     

    return 0;

}

 

 

/*

功能:测试函数能否成功接收和返回结构体中的数组值,数组利用结构体进行整体赋值

说明:若10个数据完全正确则可信度很大,地址可判断内存是否重复

输入:结构体test

输出:结构体test

*/

 

struct test fun(struct test fun1)

{

    struct test fun2;

    

    printfmystruct("fun1", &fun1);

    

    //包含数组的结构体直接赋值传递

    fun2 = fun1;

    

    printfmystruct("fun2", &fun2);

    

    return fun2;

}

 

/*

功能:输出自定义结构体名称地址内容

说明:无

输入:指向字符串的指针,指向结构的指针

输出:空

*/

 

void printfmystruct(const char * p, const struct test * structname)

{

    int i;

    

    printf("%s:\t%p:\n", p, structname);

    for (i = 0; i < 10; i++) {

        printf("%4d", structname->arr[i]);

    }

    printf("\n");

    

    return;

}

 

 

/*

功能:

说明:

输入:

输出:

*/

/*

void fun(void)

{

    return;

}

*/

 

31.内存对齐,以结构体中某个类型占位最大的字节数作为单位,分别分配给各类型(分配原则:只多不少);

/*

测试用例:

           rule 1:char double, char int

           rule 2:int int double,int double

           rule 3:①char1 char2 ... char5 int double;

char1~4,每个占一个字节,char5‘占’4个字节(其中有三个字节空着);

②“依次”  int int double, int double char

 

           rule 4:由以上三条组成;

 

         rule 0:结构体变量地址 = = 结构体内第一个数据类型变量的地址;

         rule 1,得到结构体里面最长的一个变量作为参考长度L。

         rule 2,一个变量的实际占的空间和后面紧跟变量比较,取较长size做基本单位进行填充。

         rule 3 , 如果几个变量“依次”累加的值超过‘下’一个变量类型字节数,则最后一个变量重起一行,分配 ‘下’一个变量类型字节数 大小的空间。

推论:结构体的总大小为结构体最宽基本类型成员大小的整数倍,

         问题:

结构体内部数据类型,地址不一定连续;char1 char2 ... char5 int double;

char1~4,每个占一个字节,char5‘占’4个字节(其中有三个字节空着);

问题:这些空着的字节地址有内容么,或者说可以使用吗?

rule 4,各结构体间的地址间隙 = =‘下’一个结构体体内的最后一个数据类型sizeof*2;(暂不考虑编译器等其它因素影响);

*/

#include <stdio.h>

 

int main(void)

{

         int  i = 1;

        

         struct date{

//               int month;

                  int day;

                  double hour;

//               char M;

         }d1;

         struct date2{

//               int month;

//               int day;

                  double hour;

                  char M;

         }d2;

         d1 = {

                  24,15.44

         };

         int* p;

//      printf("%p\n", &d1.month);

         printf("%p\n", &d1.day);

         printf("%p\n", &d1.hour);                         

//      printf("%p\n", &d1.M);

        

         printf("%p\n",&d1);

         printf("%d %d %d\n", sizeof(d1),sizeof(d2),sizeof(d1)-sizeof(d2));

         printf("%p\n",&d2);

         d2 = {

                  16.28,'P'

         };

//      printf("%p\n", &d2.month);

//      printf("%p\n", &d2.day);

         printf("%p\n", &d2.hour);                         

         printf("%p\n", &d2.M);

 

         return 0;

}

 

  1. typedef + 被更名量 + 应更名量;
    1. 被更名量:可以是一个或多个;
        1. ①typedef  int  length; ②typedef  sturct Adate {}  Date;   
    2. 应更名量:一般为一个;
        1. ①typedef  int  length; ②typedef  sturct Adate {}  Date;

 

  1. Typedef union Ch { int i; char [4]; } CHI;

所有成员变量所占空间只有一份,它们都公用这一份空间;

空间大小:sizeof(union ...) =  Max{ sizeof(每个成员类型) };

 

  1. 全局变量的赋值必须是确定的值或常量(带const的变量 );

 

36.***** 局部变量static后,函数执行一次后,其值不随函数的消亡而消失,即:值被保留下来了;换句话,被重新初始化(其实没有,值始终存在);

void f2() {

      Static int b = 0; //局部变量初始化;

         b++;

         Printf(“%d\t” , b);

}

int main(void) {

         f2();

         f2();

         f2();

}

输出:1 2 3

 

37.由静态本地变量地址所在地,比较得出:其就是全局变量;

 

  1. 返回本地变量地址是危险的;
    1. 业主已经把房子租给别人了,你还留着那把钥匙干嘛。

 

  1. 基本宏定义
    1. _LIEN_  行号
    2. _FIEL_  文件名(从根路径起)
    3. _DATE_   日期
    4. _TIME_   时间

 

  1. 全局变量加上static,表示该变量只能在所在编译单元中使用(主要目的:在别人已经  使用.h后,依然不能使用该标记的static函数。static关键字类似Java中private);

函数加上static ,表示该函数只能在所在编译单元使用(同上);

②变量的声明;extern int i ;放在对应的.h下;

 

  1. 标准头文件结构:防止目标头文件被重复定义;部分编译器支持:#program once
    1. #ifndef  _LIST_HEAD_
    2. #define  _LIST_HEAD_
    3. ...
    4. #endif

 

42.格式化输出的转变;

   sprintf(formata , "%%%ds" , &num);  //num = 19;

         //则,format == %19s

 

43.

 

 

展开阅读全文

没有更多推荐了,返回首页