ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C语言学习笔记(加C高级)

2020-07-10 21:36:21  阅读:196  来源: 互联网

标签:文件 arr int 高级 笔记 C语言 char 进程 指针


   1 程序编译的过程:
   2     预处理   生成.i文件
   3     编译     将预处理后的文件转换成汇编语言,生成.s文件
   4     汇编        将汇编语言变为目标代码(机器代码)生成.o 文件
   5     链接        连接目标代码,生成可执行程序
   6 
   7     预处理是C语言程序从源代码变成可执行程序的第一步,主要是C语言编译器对各种预处理命令进行处理,包括头文件的包含、宏定义的扩展、
   8 条件编译的选择等。打印出预处理之后的结果:gcc -E hello.c 或者 cpp hello.c这样我们就可以看到源代码中的各种预处理命令是如何
   9 被解释的,从而方便理解和查错。
  10 
  11     编译之前,C语言编译器会进行词法分析、语法分析(-fsyntax-only),接着会把源代码翻译成中间语言,即汇编语言。如果想看到这个中间
  12 结果,可以用-S选项。
  13 
  14 
  15 1、值常量:整型值常量、浮点型值常量(例如:0.5f)、字符型值常量('a'、'\n'、'\r')、字符串值常量("hello")、符号常量、常型常量
  16 2、变量声明:存储类型、数据类型、变量名
  17 3、合法的标识符,只能以字母和下划线开头,后面可以是数字、下划线、字母,不能是关键字(例如:char、short、int、long)
  18 4、数据的存储形式: 1、在内存中的形式:小端字节序,地址低位存数据低位,地址高位存数据高位
  19                  2、在网络中形式,大端字节序,地址高位存低位,地址低位存数据高位
  20 
  21 5、三种常见的布尔分析
  22     1、整型数的布尔判断(直接判断)
  23     2、浮点数的判断     (用范围比较方式)        
  24     3、指针的判断
  25                                                                                                                 
  26 6、a++和++a的区别:
  27     a++先返回a的值,再加a = a + 1; (表达式结束才会自增)
  28     ++a先a=a + 1,再返回原来a + 1的值(表达式完成前自增)
  29 
  30 运算符优先级:
  31     优先级        运算符         名称或含义             使用形式
  32                   []        数组下标                数组名[整型表达式]
  33                   ()        圆括号                (表达式)/函数名(形参表)
  34       1              .            成员选择(对象)        对象.成员名
  35                     ->        成员选择(指针)        对象指针->成员名
  36 -------------------------------------------------------------                    
  37                   -            负号运算符            算数类型表达式
  38                 (type)        强制类型转换            (纯量数据类型)纯量表达式
  39                   ++        自增运算符            ++纯量类型可修改左值表达式
  40                     --        自减运算符            --纯量类型可修改左值表达式
  41       2              *            取值运算符            *指针类型表达式
  42                     &            取地址运算符            &表达式
  43                     !            逻辑非运算符            纯量类型表达式
  44                     ~            按位取反                ~整型表达式
  45                   sizeof      长度运算符            sizeof表达式
  46 -------------------------------------------------------------
  47 具体祥看:https://blog.csdn.net/u014100559/article/details/90764534?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159358726719724848309940%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=159358726719724848309940&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-90764534.first_rank_ecpm_v3_pc_rank_v3&utm_term=c%E8%AF%AD%E8%A8%80%E4%BC%98%E5%85%88%E7%BA%A7%E6%8E%92%E5%BA%8F
  48 
  49 
  50 
  51                         所占字节数                    数据表示范围
  52 char                        1                         -128~127
  53 unsigned char                 1                           0~255
  54 short                        2                       -2^15~2^15-1
  55 int                            4                        -21亿~21亿
  56 long                        8(32位机上为4位)
  57 long long                    8
  58 unsigned short                2                          0~65535
  59 unsigned int                                          0~42亿
  60 
  61 
  62 防止数据溢出(上溢:溢出到范围的底部,下溢:溢出到数据的底部)
  63 整数除整数得整数,整数除浮点数(其中有一个为浮点数,则结果为浮点数)
  64 
  65 sizeof:计算某类型或某表达式所占的字节数
  66 
  67 非格式化字符
  68     输入:getchar() 可使用其使程序暂停(一次只提取一个字符)
  69     输出:putchat() 
  70 
  71 
  72 /**************************************************************************/
  73 #include <stdio.h>
  74 #define MAX(n1 , n2)((n1) > (n2) ? (n1) : (n2))
  75 
  76 int max_fun(int num1 , int num2)
  77 {
  78     return num1 > num2 ? num1 : num2;
  79 }
  80 
  81 int main()
  82 {
  83     int num1 , num2 , num3
  84     printf("input three number\n");
  85     scanf("%d,%d,%d",&num1 , &num2 , &num3);
  86     int max;
  87     max = max_fun(max_fun(num1 , num2) , num3);
  88     printf("max = %d\n",max);
  89 }
  90 /**************************************************************************/
  91 
  92 while()//先判断再执行,有可能一次都不会执行
  93 
  94 do...while()//先执行再判断,至少会执行一次
  95 
  96 for(初始化表达式 ; 判断表达式 ; 迭代表达式)
  97 {
  98     循环体
  99 }
 100 //for循环执行顺序: 初始化表达式->判断表达式->循环体->迭代表达式->判断表达式
 101 
 102 coutinue()语句
 103     功能:结束本次循环,跳过循环体中尚未执行的语句,进行下一次循环体的判断(一般结合if使用)
 104 
 105 
 106 数组:有一个首地址,后面有连续内存。
 107      大批量存储指定类型的数据,有统一访问的入口(数组名 + 下标),方便对批量数据的访问。
 108 特点:1、类型统一  2、大小固定
 109 (数组名代表了数组的首地址)(数组的维数必须是常量)   
 110 
 111 数组初始化
 112     1、静态初始化(在声明时初始化,用{}初始化)
 113     2、多态初始化(声明之后的赋值)
 114 
 115 中括号[]的本质:*(数组名 + 偏移量)
 116 例:P[1]就是*(p + 1) , 1[p]就是 *(1 + p)     
 117 
 118 bzero(目标,0,位数)    //将目标清为0
 119 memset(首地址,0,字节数)//将目标设置为0
 120 memcpy(数组1,数组2,sizeof(数组2))
 121 
 122 void* : void*指针可以接收任意类型指针,提高函数通用性。
 123 const void*是常量指针,只能改变指向,不能改变值。
 124 
 125 
 126 /*********************************************************************************/
 127 二维数组:
 128 #include <stdio.h>
 129 
 130 int main(int argc, char const *argv[])
 131 {
 132     int arr[3][2];
 133     printf("arr = %p , arr[0] = %p , &arr[0][0] = %p\n" , arr , arr[0] ,&arr[0][0]);            //值相等,但意义不一样&arr[0][0],arr[0]的类型都为int*
 134     printf("&arr[0][0] = %p,arr[0][1] = %p,&arr[1][0] = %p\n",arr[0][0],arr[0][1],&arr[1][0]); //二维数组与一维数组的存储形式都一样,都是连续内存
 135     printf("arr[0] = %p,arr[1] = %p,arr[2] = %p\n",arr[0],arr[1],arr[2]);                        //二维数组的第一维表示的是每行的首地址
 136     printf("arr[0][1] = %p,arr[1][0] = %d\n",arr[0][1],arr[1][0]);                                //声明时如果未初始化,产生的也是随机值。
 137     printf("sizeof(arr) = %ld\n",sizeof(arr[0]));                                                //总字节数
 138     printf("sizeof(arr[0]) = %ld\n",sizeof(arr[0]));                                            //sizeof(每行首地址) = 一行所占字节数
 139     printf("sizeof(arr)/sizeof(arr[0]) = %ld\n",sizeof(arr)/sizeof(arr[0]));                    //行数
 140     printf("sizeof(arr[0])/sizeof(arr[0][0]) = %ld\n",sizeof(arr[0])/sizeof(arr[0][0]));        //列数
 141     printf("sizeof(arr)/sizeof(arr[0][0]) = %ld\n",sizeof(arr)/sizeof(arr[0][0]));                //总的成员个数
 142     return 0;
 143 }
 144 /*********************************************************************************/
 145 
 146 字符串与数组
 147 字符串的本质:是一种以'\0'结尾的字符数组
 148 
 149 char ch[6] = {"china"}
 150 参数是char*,表示可读可写,所以一般用字符数组char[],如果传的是指针,则不能是
 151 指向野指针、空指针、指向常量数据区的指针,可以是指向函数栈,堆内存的指针
 152 
 153 字符串的两种表达形式:
 154     字符数组:char buf[] = "hello";
 155     字符指针:const char *str = "hello";
 156 两种表达形式看起来一样,但是实际上存在很大差异,字符指针只有一个"hello",存在于常量数据区
 157 字符数组有两"hello",一个存在于常量数据区,另外一个存在于函数栈中
 158 
 159 
 160 字符串的比较命令:
 161     int strcmp(const char *s1 , const char *s2);//区分大小,全部比较s1和s2
 162     int strncmp(const char *s1 , const char *s2 , size_t n);//区分大小写部分比较s1 s2
 163     int strcasecmp(const char *s1 , const char *s2);//忽略大小写全部比较s1,s2
 164     int strncasecmp(const char *s1 , const char *s2 , size_t n);//忽略大小写部分比较s1,s2
 165     返回值:返回值大于0 ,表示S1>S2,返回值等于0,表示S1==S2,返回值小于0,表示S1<S2
 166 
 167 字符串比较示例:
 168 #include <stdio.h>
 169 #include <string.h>//导入字符串操作的头文件
 170 
 171 int main()
 172 {
 173     const char *str1 = "hello world";
 174     const char *str2 = "helloworld";
 175     char buf1[] = "hello world";
 176     char buf2[] = "hello WORLD";
 177     int sub_1 = strcmp(str1,str2);
 178     int sub_2 = strncmp(buf1,buf2,11);
 179     int sub_3 = strcasecmp(buf1,buf2);
 180     int sub_4 = strncasecmp(buf1,buf2,9);
 181 }
 182 
 183 
 184 字符串函数与 int float 类型的转换
 185 int sscanf(const char *float,...(变量地址));//将指定格式的字符串转换成int , float型
 186 int sprintf(char *buffer,const char *format,...)//将一个格式化的字符串输出到一个目的字符串中,而printf是将一个格式化的字符串输出到屏幕
 187 
 188 
 189 定义函数正确的顺序是先定义main(),在main()之前声明其他函数,在main之后实现函数
 190 函数的四要素:头文件、功能、参数、返回值
 191 头文件:把要调用的函数声明提取过来,相当于直接声明函数
 192 功能:每个函数都要实现指定的功能才有意义
 193 参数的作用:提高函数的灵活性(输入型,输出型,输入输出型)
 194 返回值:用于保存函数运行结果
 195 
 196 函数栈:由系统自动分配,自动回收(全自动),存放形参,函数中的一般局部变量,返回值。
 197 堆内存:由程序malloc(),calloc(),realloc()去申请用free()释放,如果不释放则会内存泄漏。
 198 
 199 参数的传递方式:
 200         地址传递:(C++里的浅拷贝)
 201             作用效果:函数内的改变会影响函数外
 202             本质:通过形参指针改变实参的值
 203             判断条件:根据形参判断,如果形参是指针或者数组则一般是地址传递(特殊情况:如果只是改变形参指针的指向,而没有通过形参改变实参的值)
 204         值传递:(C++里的深拷贝)
 205             作用效果:函数内的改变不影响函数外
 206             本质:只改变形参的值,没改变实参的值
 207             判断条件:根据形参判断,如果形参是基本结构或着结构体等一般类型(非指针,非数组)
 208 
 209 /***********************************************************************************************************/
 210 变量的存储类型(存储位置不同):
 211     1、register(寄存器变量):存在寄存器中(寄存器变量可以提高运算速度,程序中不会去声明,由编译器自动生成)
 212     2、auto(自动变量):在函数栈中 
 213     3、static(静态变量):在全局数据区,不能被外部文件引用访问 
 214     4、extern(外部变量):在全局数据区,引用外部啊文件的变量
 215 
 216 静态变量:在函数中声明的静态变量
 217 
 218 静态局部变量与一般局部变量的区别:
 219     相同之处:作用域相同,都是作用于函数内
 220     不同之处:1、生命周期不同
 221             2、初始化次数不同
 222             3、初始化值不同
 223             4、存储位置不同
 224 静态全部变量与一般全局变量的区别:
 225     相同之处:1、生命周期相同(整个应用程序)
 226              2、存储位置相同(全局数据区)
 227              3、初始化次数相同
 228              4、初始化值相同
 229              5、在同一个文件中作用域相同
 230     不同之处:1、作用域不同,一般全局变量可在本文件使用,也可以被外部文件使用,静态全局变量只能用于本文件(保护,限制数据只能在本文件使用)
 231 
 232 一般函数与静态函数:
 233     在同一个文件中两种函数没有区别
 234     一般函数可作用于本文件也可以作用于外部文件,但是静态函数只能作用于本文件,不能作用于外部文件
 235     (如果需要在外部文件中调用静态函数,可以间接调用,先在一般函数中嗲用静态函数,再在外部文件调用一般函数)
 236 
 237 
 238 /****************************************************************************************************************/
 239 指针(任何指针在64位机下都是8个字节)
 240 
 241 指针使用:* &
 242 *在指针中的两个作用:
 243         1、作类型说明符:例如int *p 在声明指针时做类型说明,说明P是指针其类型为int
 244         2、作取值符:除声明之外,*都是取值符,取出地址的值
 245 &的作用:在指针中 & 只要一个作用,即为取地址
 246 
 247 * 取值会减少指针的级数,* 一级指针取值,*二级指针是取的一级指针的地址,**p取出的二级指针的值
 248 
 249 指针在使用时注意:
 250     1、指针类型必须一致
 251         错误示例: int i = 'a';
 252                   char ch1 = 'a';
 253                   int *p = &ch1;//error
 254                   float *pf = &ch1//error
 255                   char *p = (char *) &i;//指针类型可以强转
 256     2、在强制转换时不仅要看指针的类型,还要看原参数的类型
 257                   例如:char ch = 3.14;
 258                          int *p = (int*)&ch;
 259                   因为ch为char 型,一次只取一个字节,而int型一次读取4个字节,如果这样进行强转,则指针*p的值便会成为一串错误的数据
 260 
 261 空指针:声明指针时如果没有初始化地址,则赋值为NULL。
 262     例如:int *p = NULL;
 263 主要是为了后面的安全检查,如不赋值为空指针,那么这个指针将会成为野指针,野指针无法进行安全检查
 264 
 265 void *指针:可以接收任意类型的地址,也可以给任何指针赋值
 266 void *指针经常用来作函数参数,提高函数的通用性
 267 不能声明void型变量,因为编译器不知道给void类型分配多少字节
 268 
 269 以下操作是OK的,因为指针在64位机上都是8个字节,以下的操作实际上只是改变了指针指向
 270 int *p4 = &num2;
 271 void *pv = p4;        
 272 char *pc = pv;
 273 
 274 但是 int temp = *pv 这样的写法是错误的,因为 pv 的指针类型是 void 型的,不能对 void* 进行取值
 275 
 276 C语言中运算符只有以下三种是右结合性
 277 1、单目运算符
 278 2、赋值运算符
 279 3、三目运算符
 280 指针的算术运算只能由加(+)、减(-)、后自增(++)、后自减(--),不能是乘(*)、除(/)、取余(%)
 281 
 282 指针函数:返回类型为指针的函数(例如 strcpy() 、 memcpy())
 283     (注:指针函数返回参数千万不要返回一个局部变量的指针,因为局部变量在调用结束后会被自动销毁)
 284 函数指针:指向和函数的指针(int (*_) (int,int))
 285 
 286 /*******************************************************************************************/
 287 函数指针示例:
 288 #include <stdio.h>
 289 
 290 int max(int num1,int num2)
 291 {
 292     printf("max:excate\n");
 293     return num1 > num2 ? num1 : num2;
 294 }
 295 
 296 float add(float num1 , float num2)
 297 {
 298     printf("add : excate\n");
 299     return num1 + num2;
 300 }
 301 
 302 int main()
 303 {
 304     printf("main = %p , max = %p , add = %p\n",main,max,add);
 305     //int *p = max;//由于max是函数名,虽然也是个地址,但是不能用一般的指针指向它,需要用到函数指针
 306     int (*pfun)(int , int );//声明的函数指针
 307     pfun = max;//对函数指针进行赋值,此时使用pfun(int,int),与max(int,int)效果一样
 308     printf("pfun = %p , max = %p\n",pfun,max);
 309     int res = pfun(1,2);
 310     printf("pfun_res = %d\n",res);
 311 
 312     float (*pfun2)(float,float) = add;
 313     printf("pfun2 = %p , add = %p\n" , pfun2 , add);
 314     float r = pfun2(1.2,3.4);
 315     printf("r = %f\n",r);
 316 }
 317 /*******************************************************************************************/
 318 函数指针的使用:主要用于作参数,提高函数的通用性(回调函数)
 319 
 320 
 321 预处理指令:
 322     #include //静态包含
 323     #define     //宏替换
 324     #if      //条件编译
 325     #ifdef      //条件编译
 326     #ifndef     //条件编译
 327 
 328 1、预处理指令只占用编译时间,不占用调用时间
 329 2、一行只能写一个预处理指令,不是C语言语句,不需要加分号(;)
 330 
 331 宏替换:
 332     1、不带参宏  2、带参宏
 333     不带参宏示例:
 334         #define PI 3.14
 335 宏替换在预处理时会将宏名替换成宏体内容,不会进行安全检查,且如为带参宏需要注意其优先级,最好是给每一个参数都加上个小括号"()"
 336 
 337 系统的预定义宏:
 338     __FILE__    类型为 const char * , 所在文件的文件名
 339     __func__    类型为 const char * , 所在函数的函数名
 340     __LINE__    类型为 int          , 所在的行数
 341     __DATE__    类型为 const char * , 系统当前日期
 342     __TIME__    类型为 const char * , 系统当前时间
 343 
 344 /*********************************************************************************************/
 345 
 346 结构体:
 347     struct studnet                        struct 结构体类型名
 348     {                                    {
 349                                             成员类型1 成员变量1
 350                                             成员类型2 成员变量2    
 351     };                                    };
 352 
 353 声明结构体变量的格式:struct 结构体类型名 变量名
 354 1、结构体内部变量内存是连续的
 355 2、结构体成员如果没有初始化则会是随机数
 356 3、结构体类型不占内存,结构体变量才占内存,其大小为所有成员大小之和,而且与结构体成员个数和顺序有关。
 357 
 358 struct temp1        //8字节                                    
 359 {
 360     char ch1;
 361     char ch2;
 362     int  i;
 363 };
 364 
 365 struct temp2        //12字节
 366 {
 367     char ch1;
 368     int  i;
 369     char ch2;
 370 };
 371 
 372 结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续的内存空间。
 373 和数组不一样的是,结构体的大小不是所有成员大小简单的相加,需要考虑到系统在存储结
 374 构体变量时的地址对齐问题。
 375 
 376 偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体的大小是由最后一个
 377 成员的偏移量加上最后一个成员的大小。显然 (temp2),结构体变量中第一个成员的地址
 378 就是结构体变量的首地址。因此,第一个成员ch1的偏移量为0。第二个成员i的偏移量是第一个
 379 成员的偏移量加上第一个成员的大小(0+1),其值为1;第三个成员ch2的偏移量是第二个成员
 380 的偏移量加上第二个成员的大小(1+4),其值为5。
 381 
 382 根据内存对齐的方法,用最后一个成员的偏移量加上最后一个成员的大小,得出结构体大小为12
 383 
 384 结构体中的成员可以是本结构体类型的指针,不能是本结构体的变量,因为编译器不知道给它分配多少内存
 385 (可以是其他结构体的变量)
 386 
 387 结构体的定义:
 388     匿名定义:
 389         struct
 390         {
 391             char name[16];
 392             int age;
 393         }stu1 = {"zhangsan",22};//必须在声明结构体类型时声明变量
 394 
 395 
 396         struct student
 397         {
 398             char name[16];
 399             int age;
 400             struct
 401             {
 402                 int year;
 403                 int month;
 404                 int day;
 405             }bdate;
 406         };
 407 
 408 /***********************************************************************************/
 409 共用体:几个不同的变量共享一段内存的结构,成为"共用体"类型的结构
 410 (同一时刻只能做一种功能)
 411 
 412 定义共用体类型变量的一般形式为:
 413     union 共用体名
 414     {
 415         成员表列
 416     }变量表列;
 417 
 418 例如:
 419 union Data
 420 {
 421     int i;
 422     char ch;
 423     float f;
 424 }a,b,c;
 425 
 426 地址空间表示图:
 427 |地址 |1000|1001|1002|1003|
 428 |_____|____|____|____|____|
 429 |int  |____|____|____|____|        
 430 |char |____|____ ____ ____
 431 |float|____|____|____|____|
 432 
 433 以上3个变量在内存中占的字节数不同,但是都是从同一地址开始,也就是使用了覆盖技术,后面的数据覆盖了前面的数据
 434 
 435 共用体类型数据的特点:
 436     同一内存段可以用来存放不同类型的成员,但在每一瞬间只能存放其中一个成员,而不是同时存放几个
 437 
 438 /***********************************************************************************/
 439 #include <stdio.h>
 440 
 441 union stu
 442 {
 443     int i;
 444     char c;
 445     float f;
 446 }a;
 447 
 448 int main()
 449 {
 450     a.i = 0x61;//0x61为97
 451     printf("%d\n",a.i);//97
 452     printf("%c\n",a.c);//a
 453     printf("%f\n",a.f);//0.000000
 454 }
 455 /***********************************************************************************/
 456 97转换成16进制为0x00000061,因为电脑的存储发方式是小端字节序格式,因此地址在内存中的存储方式如下所示
 457 
 458 |地址 |1000|1001|1002|1003|
 459 |_____|____|____|____|____|
 460 |int  |0x61|0x00|0x00|0x00|        
 461 |char |0x61|____ ____ ____
 462 |float|0x61|0x00|0x00|0x00|
 463 
 464 共用体的用途:
 465     在数据处理中,需要对同一空间安排不同的用途,使用共用体比较方便
 466         例如:有若干人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。
 467         教师的数据包括:姓名、号码、性别、职业、职务。要求用同一表格来处理
 468 可以看出:学生和老师的数据的项目大多数是相同的,只有一个不同,学生的班级,教师的职位。
 469 struct{
 470     int num;          //成员 编号
 471     char name[10];    //成员 姓名
 472     char sex;         //成员 性别
 473     union{            //声明无名共用体类型
 474         int class;    //成员 班级
 475         char position[10];//成员 职务
 476     }category;
 477 }person[2];
 478 /***********************************************************************************/
 479 /***********************************************************************************/
 480 枚举:
 481     枚举是一种特殊类型,它的值包含在一个命名的常量集合中,这些常量称为枚举符。在实际应用中,有的
 482     变量只有几种可能取值,如人的性别只有两种可能取值,星期只有七种可能取值,在C语言种对这样取值
 483     比较特殊的变量可以定义为枚举类型。所谓枚举是指将变量的值一一列举出来,变量只限于列举出来的值
 484     的范围内取值。
 485     
 486     定义一个变量时枚举类型,可以先定义一个枚举类型名,然后再说明这个变量是该枚举类型。
 487 
 488     例如:
 489         enum weekday{sun,mon,tue,wed,thu,fri,sat};
 490     定义了一个枚举类型名enum weekday,然后定义变量为该枚举类型。
 491         enum weekday day;
 492     当然,也可以直接定义枚举类型变量,如:
 493         enum weekday{sun,mon,tue,wed,thu,fri,sat} day;
 494 需要说明的是:
 495     1、枚举元素不是变量,而是常数,因此枚举元素又称枚举常量,所以不能对枚举元素进行赋值。
 496     2、枚举元素作为常量,它们是有值的,C语言在编译时按定义的顺序使他们的值为 1,2,3...
 497 /***********************************************************************************/
 498 
 499 
 500 /***********************************************************************************/
 501 用数组存放数据时,需要事先定义数组的大小或者尽量放大数组的大小,显然浪费内存且不易更改,
 502 而链表则无这种缺点。链表是一种可动态地进行存储分配的结构
 503 链表有一个头指针(head),存放的地址指向一个元素,链表中的每个元素称为节点,每个节点由两部分组成
 504 即数据部分和指针部分。
 505  
 506 | a | b |  | a | b |  | a | b |  
 507 
 508 a为值部分,b为指针部分
 509 
 510 /***********************************************************************************/
 511 创建一个简单的链表
 512 #include <stdio.h>
 513 
 514 struct student 
 515 {
 516     int num;
 517     float score;
 518     struct student *next;
 519 };
 520 
 521 int main()
 522 {
 523     struct student a,b,c;    //三个链表节点
 524     struct student *head;
 525     struct student *p;
 526 
 527     a.num = 12345;
 528     a.score = 80;
 529     b.num = 56789;
 530     b.score = 90;
 531     c.num = 90123;
 532     c.score = 99;
 533 
 534     head = &a;
 535     a.next = &b;
 536     b.next = &c;
 537     c.next = NULL;
 538 
 539     p = head;
 540 
 541     do{
 542         printf("%d\n",p->num);
 543         p = p->next;
 544     }while(p != NULL);
 545     return 0;
 546 }
 547 /***********************************************************************************/
 548 
 549 这个链表所有节点都是在程序中定义,不是临时开辟,页没有用完就释放,这种链表称为静态链表
 550 
 551 
 552 动态链表:
 553 所谓动态链表,是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各
 554 结点数据,并建立起前后相链的关系。
 555 
 556 参考程序:
 557 #include <stdio.h>
 558 #include <stdlib.h>
 559 
 560 struct Student
 561 {
 562     int No;
 563     struct Student *next;
 564 };
 565 
 566 int main()
 567 {
 568     struct Student *p1 , *p2;
 569     struct Student *head , *p;
 570     int n = 0;//结点个数
 571 
 572     head = NULL;
 573     P1 = (struct Student *)malloc(sizeof(struct Student));
 574     printf("请输入第1个学号\n");
 575     scanf("%d",&p1->No);
 576     p2 = p1;
 577     while(p1->No != 0)
 578     {
 579         n++;
 580         if(n == 1)
 581         {
 582             head = p1;
 583         }
 584         else
 585         {
 586             p2->next = p1;
 587         }
 588         p2 = p1;
 589         printf("请输入学号,输入0终止:\n");
 590         p1 = (struct Student *)malloc(sizeof(struct Student));
 591         scanf("%d",&p1->No);
 592     }
 593     p2->next = NULL;
 594     p = head;
 595     printf("\n学号为:\n");
 596     while(p != NULL)
 597     {
 598         printf("%d\n",p->No);
 599         p = p->next;
 600     }
 601     return 0;
 602 }
 603 /***********************************************************************************/
 604 静态链表和动态链表的区别:
 605     1、静态链表是用类似于数组方法实现的,是顺序的存储结构,物理地址上是连续的,而且需要
 606 预先分配地址空间大小。所以静态链表的初始化长度一般是固定的,在做插入和删除操作时不需要移
 607 动元素,仅需要改指针。
 608     2、动态链表是用内存申请函数(malloc())动态申请内存的,所以在链表的长度上没有限制。
 609     因为是动态申请内存的,所以每个节点的物理地址不连续,要通过指针来顺序访问。    
 610 
 611 单向循环链表:
 612     将单链表中尾节点的指针由空改为指向头结点(或第一个元素节点),就使得整个单链表形成了一个环
 613     这种头尾相接的单链表称为单向循环链表。
 614 
 615          __________________________________________________    
 616         |                                                   |            
 617         v                                                   |    
 618     |head|next| -> | A |next| -> | B |next| -> | C |next| --
 619 
 620                          __________________________________
 621                         |                                   |            
 622                         v                                   |    
 623     |head|next| -> | A |next| -> | B |next| -> | C |next| --
 624 
 625 
 626 双向链表:
 627     在单向链表的结点中增加一个指向其前驱的pre指针,该链表中第一个结点的前驱结点为NULL
 628     最后一个结点的后继结点为NULL;
 629                                     ______________         _______________        
 630                                    |               |        |               |
 631                                    v              |     v               |
 632     |before|head|next| -> |before| A |next| -> |before| B |next| -> |before| C |next|-> NULL 
 633                   NULL<-------|
 634 
 635 双向循环链表:
 636     双向循环链表直接体现为"双向和循环",一般的单链表只有结点数据data和next指向地址,而在
 637     此需要增加前面部分的 pre 指向地址,同时还需要循环。
 638 
 639 
 640 
 641 /***********************************************************************************/
 642 树与二叉树:
 643 树:
 644     树形结构是一种典型的非线性数据结构,体现在数据元素之间有明显的层次关系
 645 定义:树是由n个节点构成的有限集合,n大于等于零,节点数为零的树称为空树,节
 646 点数大于零的树称为非空树
 647 
 648 一颗非空树满足以下条件:
 649     1、有且仅有一个被称为根(R)的特殊节点,其余所有节点都可由节点经过一定的分支得到,而根节点 R 没有前驱节点
 650     2、当n > 1时,除根节点R外的其他节点被分成 m 个互不相交的子集,T1 ,T2 ,....Tm,其中每个自己Ti本身又是一棵树,被称为R节点的子树
 651 
 652 树的定义时递归定义,即每个子树的定义也是按照上面的过程完成的。
 653 
 654 相关名词:
 655     1、节点
 656     2、节点的度
 657     3、树的度
 658     4、叶子节点
 659     5、分支节点
 660     6、节点的层次
 661     7、树的深度
 662 
 663  双亲:即上层的那个节点(直接前驱)
 664  孩子:即下层节点子树的根
 665 
 666 二叉树:
 667     二叉树与树完全不同,树的根不允许为空,而二叉树的根允许为空,且二叉树每个节点最多允许2个节点
 668 
 669     二叉树性质:1、在二叉树的第 i 层上至多有 2^i-1 个节点
 670                2、深度为 k 的二叉树最多有 2^k-1 个节点
 671 
 672     满二叉树:一棵树的深度为 K ,且有2^k-1 个节点的二叉树。
 673 
 674     完全二叉树:最大深度与最小深度相差不超过 1 
 675 
 676 二叉树的遍历:
 677     前序遍历、中序遍历、后序遍历
 678     示例:
 679                     A
 680                    / \            
 681                   B   C
 682                  / \    
 683                 D   E
 684 前序遍历:先根再左再右    ABDEC
 685 中序遍历:先左再根再右    DBEAC
 686 后序遍历:先左再右再根    DEBCA      
 687 
 688 
 689 
 690 /***********************************************************************************/
 691 文件操作:
 692     1、打开文件
 693     2、文件读/写
 694     3、关闭文件
 695 
 696 标准I/O(不区分操作系统,在任何系统中都可以使用):
 697 
 698     文件常见的操作:
 699         fopen/fclose
 700         fgets/fputs
 701         fgetc/fputc
 702         fwrite/fread
 703         fseek
 704 FILE* fopen(const char *path ,const char *mode);
 705 FILE* freopen(const char *restrict pathname,const char*restrict type,FILE *restrict fp);//用于重定向
 706 FILE *fdopen(int filedes,const char *type);
 707 
 708 fseek,用于将指针移到文件的某一个位置
 709 语法:
 710     status = fseek(fileID,offset,origin)
 711 
 712     fileID是fopen打开时产生的整数标识,大于 0 时,表示文件成功打开,在文件中,offset是对于origin位置
 713     开始移动的整数,origin有三种状态,bof,cof,eof,其分别表示文件的开始位置,当前位置,和末尾位置,如果操作
 714     成功,则状态返回 0,否则返回-1
 715 
 716 
 717 fopen() 打开由 path 指定的一个文件,mode参数如下:
 718 ---------------------------------------------------------------------------------------------------------
 719 |    r或者rb    |    打开只读文件,该文件必须存在                                                            |
 720 |      r+或r+b    |     打开可读写的文件,该文件必须存在。                                                       |
 721 |      w或wb        |   打开只写文件,若文件存在则文件长度清为0,即会擦除文件以前内容,若文件不存在则会建立该文件     |
 722 | w+或w+b或wb+  |   打开可读写文件,若文件存在则文件长度清为0,即会擦除文件以前内容,若文件不存在则会建立该文件   |
 723 |      a或ab      |   以追加的方式打开只写文件,若文件不存在,则会建立文件,如果文件存在,写入的数据                  |        
 724 |                    会被加到文件尾,即文件原先内容会被保留                                                     |
 725 |    a+或a+b或ab+|    以追加的方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,从头读取,但是写入  |
 726 |                    的数据会被加到文件尾,即文件原先的内容会被保留                                             |
 727 ---------------------------------------------------------------------------------------------------------|
 728 
 729 /***********************************************************************************/
 730 fopen示例:
 731 #include <stdio.h>
 732 
 733 int main()
 734 {
 735     FILE* fp;
 736     int i;
 737     char name[8];
 738     fp = fopen("path","r");
 739     fscanf(fp,"%s",name);
 740     fclose(fp);
 741     for(i = 0 ; i < 8 ; i++)
 742     {
 743         printf("%c",name[i]);
 744     }
 745     printf("\n");
 746     return 0;
 747 }
 748 /***********************************************************************************/
 749 读写的函数:
 750     一次读写一个字节:
 751         fgetc/getchar/get
 752         fputc/putchar/putc
 753     
 754     一次去写一行:
 755         fgets/gets        
 756         fputs/puts
 757     gets不使用,因为gets获取一行数据是指导EOF而结束的,如果变量大小小于字符大小,则会造成内存溢出
 758     puts函数主要用于向标准输出设备写入字符串并换行,即会自动写一个'\n'
 759     fputs函数用来向指定文件写入一个字符串(不换行)
 760 
 761 
 762     fwrite/fread
 763     函数原型:
 764         size_t fread(void *buffer,size_t num_bytes,size_t count,FILE *fp);
 765         size_t fwrite(const void *buffer,size_t num_bytes,size_t count,FILE *fp);
 766 
 767       对fread()而言,buffer是接收读入数据的内存区的指针。
 768       对fwrite()而言,buffer是写入到那个文件的信息的指针。
 769       count的值确定读/写多少项,每项长度等于num_bytes。
 770       fp是指向事先打开的流的指针。
 771       正常情况下,fread()返回读入的项数,fwrite()返回写出的项数。
 772       只要文件按二进制打开,fread()和fwrite()就可以读/写各类信息。以下程序先向文件写double,int和long型数据,然后再读回。
 773 
 774 -----------------------------------------------------------------------------
 775                     打开一个标准I/O流的六种不同方式
 776 
 777         限制                    r       w       a      r+       w+
 778     文件必须已存在            √                        √
 779     擦除文件以前的内容                √                        √
 780     流可以读                    √                        √        √
 781     流可以写                            √        √        √        √
 782     流只可在尾端处写                            √
 783 ------------------------------------------------------------------------------
 784 
 785 FILE指针:每个被使用的文件都在内核中开辟一个区域,用来存放文件的相关信息,这些信息是保存在一个结构体类型的
 786 变量中,该结构体类型是由系统定义的,取名为FILE
 787 
 788 标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用 FILE* 来描述
 789     
 790     流(stream):
 791         定义:所有的I/O操作仅是简单的从程序移进或者移出,这种字节流,就称为流
 792         分类:文本流/二进制流
 793 
 794         文本流:
 795             定义:在流中处理数据是以字符出现,在文本流中,'\n' 被转换成回车符CR和换行符LF的ASCII码0DH和0AH
 796                 而当输出时,0DH和0AH被转换成'\n'
 797             数字2001在文本流中的表示方法为'2','0','0','1'
 798             ASCII: 50 48 48 49
 799 
 800         二进制流:
 801             定义:流中处理的是二进制序列,若流中有字符,则用一个字节的二进制ASCII码表示;若是数字,则用对应的二进制数表示。对'\n'不进行变换
 802                 数字2001在二进制流中的表示方法为 00000111 11010001
 803 
 804 /***********************************************************************************/
 805 文件I/O(系统I/O):
 806     文件I/O相关操作函数
 807         open()  creat()  close()  read()  write()  lseek()  
 808  
 809 int open(const char *pathname , int flags);
 810 int open(const char *pathname , int flags , mode_t mode);
 811 int creat(const char *pathname , mode_t mode);
 812 
 813 pathname 是表示欲打开的文件路径字符串
 814 flags 是表示打开方式:
 815     O_RDONLY 以只读方式打开文件
 816     O_WRONLY 以只写方式打开文件
 817     O_RDWR 以可读写方式打开文件. 上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(|)运算符组合.
 818     O_CREAT 若欲打开的文件不存在则自动建立该文件.
 819     O_EXCL 如果O_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否则将导致打开文件错误. 此外, 若O_CREAT 与O_EXCL 同时设置, 并且欲打开的文件为符号连接, 则会打开文件失败.
 820     O_NOCTTY 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
 821     O_TRUNC 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 而原来存于该文件的资料也会消失.
 822     O_APPEND 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面.
 823     O_NONBLOCK 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中.
 824     O_NDELAY 同O_NONBLOCK.
 825     O_SYNC 以同步的方式打开文件.
 826     O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接, 则会令打开文件失败.
 827     O_DIRECTORY 如果参数pathname 所指的文件并非为一目录, 则会令打开文件失败。注
 828 
 829 mode 表示打开权限
 830     S_IRWXU00700 权限, 代表该文件所有者具有可读、可写及可执行的权限.
 831     S_IRUSR 或S_IREAD, 00400 权限, 代表该文件所有者具有可读取的权限.
 832     S_IWUSR 或S_IWRITE, 00200 权限, 代表该文件所有者具有可写入的权限.
 833     S_IXUSR 或S_IEXEC, 00100 权限, 代表该文件所有者具有可执行的权限.
 834     S_IRWXG 00070 权限, 代表该文件用户组具有可读、可写及可执行的权限.
 835     S_IRGRP 00040 权限, 代表该文件用户组具有可读的权限.
 836     S_IWGRP 00020 权限, 代表该文件用户组具有可写入的权限.
 837     S_IXGRP 00010 权限, 代表该文件用户组具有可执行的权限.
 838     S_IRWXO 00007 权限, 代表其他用户具有可读、可写及可执行的权限.
 839     S_IROTH 00004 权限, 代表其他用户具有可读的权限
 840     S_IWOTH 00002 权限, 代表其他用户具有可写入的权限.
 841     S_IXOTH 00001 权限, 代表其他用户具有可执行的权限.
 842 
 843 
 844 这些函数都会返回一个文件描述符fp来表示当前打开的文件,文件描述符是一个非负整数,打开现存文件或者新建文件时,内核会返回一个文件描述符,用于指代被打开的文件,
 845 所有执行I/O操作的系统调用都通过文件描述符。进程刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。
 846 
 847 
 848 权限的修改和阅读:
 849     权限分类:
 850             r      w      x
 851             4      2      1
 852 
 853     示例:
 854         -rwxrwxrwx   0777最高权限,采用8进制方法进行表示
 855         -rw-r--r--     0644
 856 
 857 标准I/O和文件I/O的区别:
 858     标准I/O是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性,标准I/O库处理很多细节
 859     例如缓存分配,以优化长度执行I/O等。标准I/O提供了三种类型的缓存。
 860         1、全缓存:当填满标准I/O缓存后才进行实际的I/O操作
 861         2、行缓存:当输入或输出中遇到新行符时,标准I/O库执行I/O操作
 862         3、不带缓存:stderr就是了
 863 
 864     文件I/O被称为不带缓存的I/O,不带缓存指的是每个read, write , 都调用内核中的一个系统调用,也就是一般所说的低级I/O
 865 
 866     文件I/O使用文件描述符来表示打开的文件,所以可以访问不同类型的文件,如普通文件、管道文件等。而标准I/O使用的是FILE(流)
 867     来表示打开的文件,通常只用来访问普通文件。
 868 
 869 文件I/O使用示例:
 870 /***********************************************************************************/
 871 #include <unistd.h>
 872 #include <stdio.h>
 873 #include <sys/types.h>
 874 #include <sys/stat.h>
 875 #include <fcntl.h>
 876 
 877 int main(void)
 878 {
 879     int f;
 880     int size;
 881     char buf[100];
 882     f = open(path , O_RDONLY);   //path为文件路径
 883     size = read(f , buf , sizeof(buf));
 884     printf("size = %d , buf = %s\n",size , buf);
 885     close(f);
 886     return 0;
 887 }
 888 /***********************************************************************************/
 889 
 890 
 891 /***********************************************************************************/
 892                                     文件和目录
 893 以下三个函数可以获取文件/目录的属性信息:
 894 #include <unistd.h>
 895 #include <sys/types.h>
 896 #include <sys/stat.h>
 897 
 898 int stat(const char *path, struct stat *buf);
 899 int fstat(int fd, struct stat *buf);
 900 int lstat(const char *path, struct stat *buf);
 901 
 902 三个函数的返回:若成功则为0,若出错则为-1,并且设置errno.
 903 给定一个path的情况下:
 904 stat函数返回一个与此命名文件有关的信息结构
 905 fstat函数获得已在描述符filedes上打开的文件的有关信息
 906 lstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息。
 907 
 908 
 909 掌握目录操作相关焊数
 910 chdir()
 911 opendir()
 912 readdir()
 913 
 914 /***********************************************************************************/
 915 
 916 
 917 /***********************************************************************************/
 918                                 动态库和静态库
 919 什么是库:
 920     库是共享程序代码的方式,一般分为静态库和动态库
 921 静态库:
 922     链接时完整的拷贝至可执行文件中,被多次使用就有多份冗余拷贝
 923 动态库:
 924     链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省空间。
 925 
 926 使用静态库和动态库的好处:
 927     1、使用静态库的好处
 928         模块化,分工合作
 929         避免少量的改动经常导致大量的重复编译链接
 930         也可以重用(注意不是共享内存)
 931     2、使用动态库的好处:
 932         使用动态库可以将最终可执行的文件体积缩小
 933         使用动态库多个应用程序共享内存中的同一份库文件,节省资源
 934         使用动态库可以不重新编译链接可执行程序的前提下,更新动态库文件达到更新应用程序的目的
 935 /***********************************************************************************/
 936 
 937 /***********************************************************************************/
 938                                     进程/线程
 939 创建   执行     消亡
 940 进程是一个独立的可调度的任务
 941 进程是一个程序的一次执行的过程
 942 
 943 进程的定义:"进程"是操作系统的最基本,最重要的概念之一。但迄今为止对这一概念还没有一个确定的统一描述。
 944     下面给出几种对进程的定义描述。进程是程序的一次执行,进程是可以并行执行的计算,进程是一个程序与其
 945     使用的数据在处理机上顺序执行时发生的活动。进程是程序在一个数据集合上的运行过程。它是系统进行资源分
 946     配和调度的一个独立单位。
 947 
 948 进程的特征:
 949     多态性:是程序的一次执行;
 950     并发性:进程是可以并发执行;
 951     独立性:是系统进行资源分配和调度的一个独立单位
 952     异步性:进程间的相互制约,使进程执行具有间隙、
 953     结构性:进程是具有结构的
 954 
 955 进程和程序的区别:
 956     1、程序是永存的,进程是暂时的,是程序在数据集上的一次执行,有创建有撤销,存在是暂时的
 957     2、程序是静态的观念,进程是动态的观念
 958     3、进程具有并发性,而程序没有
 959     4、进程是竞争计算机资源的基本单位,程序不是
 960     5、进程和程序不是一一对应的,一个程序可以对应多个进程可执行同一程序;一个进程可以执行一个或多个程序
 961 
 962 进程创建:fork()     会复制进程(父 ,子)  vfork() 
 963 #include <sys/type.h>
 964 #include <unistd.h>
 965 #include <stdio.h>
 966 #include <stdlib.h>
 967 
 968 int main(){
 969 
 970     pid_t pid; 
 971     pid = fork();   //当fork调用成功后,子进程开始从fork后开始执行
 972 
 973     //创建进程失败
 974     if(-1 == pid){
 975         perror("fork failed");
 976         return -1;
 977 
 978     //父进程
 979     }else if(pid > 0){
 980             //pid用于接收当前进程id, ppid用于接收父进程id
 981             printf("parent : pid = %d , ppid = %d\n", getpid(), getppid());
 982             sleep(1);//系统延时
 983 
 984     //子进程
 985     }else if(pid == 0){
 986             printf("child: pid = %d, ppid = %d\n", getpid(), getppid());
 987             sleep(1);
 988     }
 989     return 0;
 990 }
 991 
 992 返回值 pid : 0:子进程
 993              子进程pid(大于 0 的整数):父进程
 994              -1:出错
 995 
 996 ( pid_t 的底层代码就是一个 int )
 997 
 998 
 999 fork() 和 vfork() 的区别:
1000     fork()和 Vfork()都可以创建一个进程,但 vfork() 是由 fork()封装得来的
1001 其实 fork 创建的子进程相对独立,当用 fork 后子进程与父进程同时各自进行自己的程序互不影响,但只
1002 有一个终端接受他们两个的输出,所以并不是子进程与父进程随即调用,而只是在同时执行父进程和子进程,
1003 只是随机输出,子进程与父进程仍各自有序。
1004 
1005 (1)使用fork创建一个进程时,子进程只是完全复制父进程的资源。这样得到的子进程独立于父进程,具有
1006 良好的并发性。而使用vfork创建一个子进程时,操作系统并不将父进程的地址空间完全复制到子进程,用vfork
1007 创建的子进程共享父进程的地址空间,也就是说子进程完全运行在父进程的地址空间上。子进程对该地址空间中
1008 任何数据的修改同样为父进程所见。
1009 
1010 (2)使用fork创建一个子进程哪个进程先运行取决于系统的调度算法。而vfork创建一个进程时,vfork保证子进程
1011 先运行,当他调用exec或exit之后,父进程才可能被调读运行。如果在调用exec或exit之前子进程要依赖父进程的
1012 某个行为,就会导致死锁。
1013 
1014 因为使用fork创建一个进程时,子进程需要将父进程几乎每种资源都复制,所以fork是一个开销很大的系统调用,
1015 这些开销并不是所有情况都需要的。比如fork一个进程后,立即调用exec执行另一个应用程序,那么fork过程中子
1016 进程对父进程地址空间的复制将是一个多余的过程。vfork不会拷贝父进程的地址空间,这大大减小了系统的开销。
1017 
1018 当用vfork创建进程时,若以return 0 结束则释放局部变量,以exit(0)结束则不会释放。
1019 
1020 (p185)fork一个子进程,该子进程中的var和globvar记录的是父进程中var和globvar中的值,而fork之后父进程对变量的改变则不对子进程产生影响。
1021 
1022 vfork一个子进程,先执行子进程,子进程沿用父进程中的变量,当以exit(0)结束后,父进程可仍沿用子进程中的变量。
1023 当以return 0 结束则释放局部变量,父进程再引用时则会为系统给的随机值。
1024 
1025 
1026 在任何位置执行 exit() 都会结束进程(会刷新缓存),_exit() 不会刷新缓存
1027 
1028 atexit() 注册退出函数
1029 int atexit(void(* function)(void));
1030 把function注册到系统中,退出的时候会调用这个函数
1031 
1032 excel() 执行其他的程序代码数据段全部被新的程序的代码段和数据段取代,只要执行成功,就不会返回了
1033         用来执行参数path字符串所代表的文件路径(绝对路径),第二个参数代表执行文件时传递的agrv,最后一个参数必须是空指针
1034         excel("/bin/cat","/etc/passwoed",NULL);
1035                命令路径        参数路径
1036 
1037 wait() 和 waitpid()的区别:
1038     调用 wait() 函数使程序进行阻塞,直到任一个子进程结束或者是该进程接收到了一个信号为止。如果该进程没用子进程或者其子进程已经结束,wait() 函数会立即返回。
1039     调用 waitpid() ,参数 pid 指定想等待的子进程ID,值 -1 表示第一个终止的子进程,参数 options 指定附加页,最常用的是 WNOHANG ,通知内核在没有已终止子进程的时候不要阻塞
1040 当正常返回的时候,waitpid返回收到的子进程的进程ID;
1041 如果设置了选项 WNOHANG ,而调用中waitpid 发现没有已退出的子进程可收集,则返回0
1042 如果调用中出错,则返回 -1 ,这时 errno 会被设置成相应的值以指示错误所在 
1043 /***********************************************************************************/
1044 
1045 /***********************************************************************************/
1046 
1047                                                     网络编程
1048 DNS:常用的有114.114.114.114 /  8.8.8.8 用来解析数据
1049 子网掩码:用于判断IP是不是同一个网段
1050 
1051 例如:有两个IP,192.168.0.100  ,  192.168.0.8 两个IP需要通信,则两个IP与子网掩码作按位与操作
1052 192.168.0.100 & 0xff.0xff.0xff.0 = 192.168.0.0
1053 192.168.0.8   & 0xff.0xff.0xff.0 = 192.168.0.0
1054 两次的值相等,则说明两个IP在同一网段
1055 
1056 网络字节序都是大端字节序
1057 TCP:
1058 TCP服务端流程
1059     1、创建套接字socket
1060     2、绑定端口 bind
1061     3、监听是否有客户端连接 Listen
1062     4、接受    accept
1063     5、读/写 send/recv
1064     6、关闭  close
1065 
1066 TCP客户端:
1067     1、创建套接字  socket
1068     2、主动连接别人 connect
1069     3、读/写 send/recv   
1070     4、关闭  close
1071 
1072 UDP:
1073 UDP服务器流程:
1074     1、创建一个套接字 socket
1075     2、设置socket属性 setsockept
1076     3、绑点IP地址,端口等信息到socket上,用函数bind
1077     4、循环接收数据,用函数数recvfrom
1078     5、关闭网络连接
1079 
1080 UDP客户端流程:
1081     1、创建一个套接字 socket
1082     2、设置socket属性,用函数setsockeopt
1083     3、绑点IP地址,端口等信息到socket上,用函数bind
1084     4、设置对方的IP地址和端口等属性; 
1085     5、发送数据,用函数数sendto
1086     6、关闭网络连接
1087 
1088 
1089             OSI模型                  TCP/IP协议
1090             应用层                        应用层
1091             表示层
1092             会话层        
1093             传输层                        传输层
1094             网络层                        网络层
1095             数据链络层                    数据链络层
1096             物理层                        物理层
1097 
1098 
1099 TCP和UDP都是OSI模型中传输层的协议,TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输
1100 
1101 UDP补充:
1102    UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务。并且它是将应用程序发来的
1103    数据在收到的那一刻,立刻按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况下,
1104    UDP也无法进行流量控制等避免网络拥塞的行为。此外,传输途中如果出现了丢包,UDO也不负
1105    责重发。甚至当出现包的到达顺序乱掉时也没有纠正的功能。如果需要这些细节控制,那么不得
1106    不交给由采用UDO的应用程序去处理。换句话说,UDP将部分控制转移到应用程序去处理,自己
1107    却只提供作为传输层协议的最基本功能。UDP有点类似于用户说什么听什么的机制,但是需要用
1108    户充分考虑好上层协议类型并制作相应的应用程序。
1109 
1110 TCP补充:
1111   TCP充分实现了数据传输时各种控制功能,可以进行丢包的重发控制,还可以对次序乱掉的分包
1112   进行顺序控制。而这些在UDP中都没有。此外,TCP作为一种面向有连接的协议,只有在确认通信
1113   对端存在时才会发送数据,从而可以控制通信流量的浪费。TCP通过检验和、序列号、确认应答、
1114   重发控制、连接管理以及窗口控制等机制实现可靠性传输。
1115 
1116 
1117 TCP与UDP区别总结:
1118 1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
1119 2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保   证可靠交付
1120 3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
1121   UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
1122 4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
1123 5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
1124 6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
1125 
1126 
1127 
1128 
1129 
1130 
1131 排序算法:
1132     1、选择排序
1133     2、冒泡排序
1134     3、快速排序
1135     4、希尔排序
1136     5、桶排序
1137     6、计数排序
1138     7、插入排序
1139     8、归并排序
1140     9、堆排序
1141     10、基数排序
1142 
1143 1、选择排序:
1144 /**********************************************************************************************************************/
1145 #include <stdio.h>
1146 #define ARRSIZE 5
1147 
1148 void ChoiceSort(int *arr)
1149 {
1150     int i,j,min,temp;
1151     for(i = 0 ; i < ARRSIZE-1 ; i++)
1152     {
1153         min = i;
1154         for(j = i+1 ; j < ARRSIZE ; j++)
1155         {
1156             if(arr[j] < arr[min])      //正序排序
1157                 min = j;
1158         }
1159         if(min != i)
1160         {
1161             temp = arr[min];
1162             arr[min] = arr[i];
1163             arr[i] = temp;
1164         }
1165     }
1166     for(i = 0 ; i < ARRSIZE ; i++)
1167         printf("%d\t",arr[i]);
1168 }
1169 
1170 int main(void)
1171 {
1172     int arr[ARRSIZE] = {0};
1173     int i;
1174     for(i = 0 ; i < ARRSIZE ; i++)
1175         scanf("%d",&arr[i]);
1176     ChoiceSort(arr);
1177     return 0;
1178 }
1179 
1180 /**********************************************************************************************************************/
1181 
1182 /**********************************************************************************************************************/
1183 2、冒泡排序:
1184     #include <stdio.h>
1185 #define ARRSIZE 5
1186 
1187 void BubbleSort(int *arr)
1188 {
1189     int i,j,temp,flag;
1190     for(i = 1 ; i < ARRSIZE ; i++)
1191     {
1192         flag = 0;
1193         for(j = 0 ; j < ARRSIZE-i ; j++)
1194         {
1195             if(arr[j] > arr[j+1])
1196             {
1197                 temp = arr[j];
1198                 arr[j] = arr[j+1];
1199                 arr[j+1] = temp;
1200                 flag = 1;
1201             }
1202         }
1203         if(!flag)
1204             break;
1205     }
1206     for(i = 0 ; i < ARRSIZE ; i++)
1207         printf("%d\t",arr[i]);
1208     printf("\n");
1209 }
1210 
1211 int main(void)
1212 {
1213     int i;
1214     int arr[ARRSIZE] = {0};
1215     for(i = 0 ; i < ARRSIZE ; i++)
1216         scanf("%d",&arr[i]);
1217     BubbleSort(arr);
1218     return 0;
1219 }
1220 
1221 /**********************************************************************************************************************/
1222 
1223 /**********************************************************************************************************************/
1224 3、快速排序:
1225 #include <stdio.h>
1226 
1227 void QuickSort(int *arr,int num)
1228 {
1229     int i = 0;
1230     int j = num - 1;
1231     int x = arr[0];
1232     if(num > 1)
1233     {
1234         while( i != j)
1235         {
1236             for(; i < j ; j--)
1237             {
1238                 if(arr[j] < x)
1239                 {
1240 
1241                     printf("j-- a[i] = %d,arr[j] = %d\n",arr[i],arr[j]);
1242                     arr[i] = arr[j];
1243                     break;
1244                 }
1245             }
1246             for(; i < j ; i++)
1247             {
1248                 if(arr[i] > x)
1249                 {
1250                     printf("i++ a[j] = %d,arr[i] = %d\n",arr[j],arr[i]);
1251                     arr[j] = arr[i];
1252                     break;
1253                 }
1254             }
1255             arr[i] = x;
1256         }
1257         QuickSort(arr,i);
1258         QuickSort(arr + i + 1 , num - i - 1); 
1259     }
1260 }
1261 
1262 int main(void)
1263 {
1264     int i;
1265     int arr[7] = {49,38,65,97,76,13,27};
1266     printf("old:");
1267     for(i = 0 ; i < 7 ; i++)
1268     {
1269         printf("%d\t",arr[i]);
1270     }
1271     printf("\n");
1272     QuickSort(arr,7);
1273 #if 1
1274     printf("new:");
1275     for(i = 0 ; i < 7 ; i++)
1276     {
1277         printf("%d\t",arr[i]);
1278     }
1279 #endif
1280     printf("\n");
1281     return 0;
1282 }
1283 
1284 /**********************************************************************************************************************/
1285 
1286 /**********************************************************************************************************************/
1287 4、希尔排序:
1288 
1289 /**********************************************************************************************************************/
1290 
1291 /**********************************************************************************************************************/
1292 
1293 5、桶排序:
1294 /**********************************************************************************************************************/
1295 
1296 /**********************************************************************************************************************/
1297 6、计数排序:
1298 /**********************************************************************************************************************/
1299 
1300 /**********************************************************************************************************************/
1301 7、插入排序:
1302 /**********************************************************************************************************************/
1303 
1304 /**********************************************************************************************************************/
1305 
1306 8、归并排序:
1307 /**********************************************************************************************************************/
1308 
1309 /**********************************************************************************************************************/
1310 
1311 9、堆排序:
1312 /**********************************************************************************************************************/
1313 
1314 /**********************************************************************************************************************/
1315 
1316 10、基数排序:
1317 /**********************************************************************************************************************/
1318 
1319 /**********************************************************************************************************************/
1320 
1321 strlen的C语言实现:
1322 #include <stdio.h>
1323 
1324 int my_strlen(char *dat)
1325 {
1326     int n = 0;
1327     while(*dat != '\0')
1328     {
1329         n++;
1330         dat++;
1331     }
1332     return n;
1333 }
1334 
1335 int main(void)
1336 {
1337     char arr[] = "123456";
1338     int num = 0;
1339     num = my_strlen(arr);
1340     printf("num = %d\n",num);
1341     return 0;
1342 }    
1343 /**********************************************************************************************************************/
1344 
1345 /**********************************************************************************************************************/
1346 strcpy的C语言实现:
1347 #include <stdio.h>
1348 
1349 char* strcpy_0(char *dest , const char *src)
1350 {
1351     char *address = dest;
1352     while((*dest++ = *src++) != '\0');
1353     return address;
1354 }
1355 
1356 int main(void)
1357 {
1358     char arr0[7] = "123456";
1359     char arr1[7] = "123345";
1360     int i;
1361     char *ch;
1362     ch = strcpy_0(arr0 , arr1);
1363     for(i = 0 ; i < 6 ; i++)
1364         printf("%c",arr0[i]);
1365     printf("\n");
1366 }
1367 /**********************************************************************************************************************/
1368 
1369 /**********************************************************************************************************************/
1370 strcat的C语言实现:
1371 #include <stdio.h>
1372 
1373 char* strcat_0(char *dest ,const char *src)
1374 {
1375     char *address = dest;
1376     while(*dest != '\0')
1377         dest++;
1378     while(*dest++ = *src++);
1379     return address;
1380 }
1381 
1382 int main(void)
1383 {
1384     char arr0[10] = "123";
1385     char arr1[] = "78";
1386     char *ch = NULL;
1387     ch = strcat_0(arr0,arr1);
1388     printf("%s\n",ch);
1389     printf("%d\n",sizeof(arr0));
1390 
1391     return 0;
1392 }
1393 /**********************************************************************************************************************/
1394 
1395 /**********************************************************************************************************************/
1396 strcmp的C语言实现:
1397 #include <stdio.h>
1398 
1399 int strcmp_0(char *str1 , char *str2)
1400 {
1401     while(*str1 == *str2)
1402     {
1403         if(*str1 == '\0')
1404             return 0;
1405         str1++;
1406         str2++;
1407     }
1408     return *str1 - *str2;
1409 }
1410 
1411 int main(void)
1412 {
1413     int num = strcmp_0("123432432","123");
1414     printf("%d\n",num);
1415 
1416     return 0;
1417 }
1418 /**********************************************************************************************************************/
1419 
1420 /**********************************************************************************************************************/

 

标签:文件,arr,int,高级,笔记,C语言,char,进程,指针
来源: https://www.cnblogs.com/jiayezi/p/13281305.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有