• C学习笔记 知识集锦(二)


     1. 数组和指针 2. 字符串赋值 3. memset&memcpy 4. 机器数和真值,原码,反码和补码 5. 文件指针和文件描述符 6. 内存泄露和内存损坏 7. 什么是不可移植的程序 8. 动态库文件和静态库文件 9. make的行为

    10. 库函数调用和系统调用

      数组和指针

        数组:同类型的数的集合

          特点: 1. 数据类型一致 2. 大小固定 3. 内存空间连续 4. 数组名本质是指针常量,是该组的地址

          初始化: int a [10] = {''} = 0; 也可以使用循环来赋空,也可以使用memset来赋空,全部赋为某个值的时候可以使用memset,当有不同值的时候不可以

     1 #include "stdio.h"
     2 int main (void) 
     3 {
     4     int a[] = {1,2,3,4,5,6,7,8,9,10};
     5     int n = sizeof(a)/sizeof(int);
     6     int *p = &a[0];
     7     
     8     printf("n = %d
    ", n);
     9     printf("p = %p
    ", p);
    10     printf("&a = %p
    ", &a);
    11     p++;
    12     printf("p = %p
    ", p);
    13 //    (&a)++;   /a++;                 //error: lvalue required as increment operand
    14 //    printf("&a = %p
    ", &a);
    15     return 0;
    16 }
    17 n = 10
    18 p = 0x7ffe820c4770
    19 &a = 0x7ffe820c4770
    20 p = 0x7ffe820c4774

            void *memset (void *s, int ch,size_t n);

            void *memcpy (void *dest, void *src,size_t n);

            一维数组的初始化,后面可以决定前面

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

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

              int a[] = {1,2,3,4,5};    //合法,后面决定前面的大小

            二维数组的初始化,二维数组不可以缺省行,但可以缺省列,且二维数组名是行指针,即a+1是跳一行

              int a[2][3] = {1,2,3,4,5,6};    //合法,很标准的二维数组的赋值

              int a[2][3] = {1,2,3,4,5,};    //合法,后面一个默认为0

              int a[2][3] = {{1,2,3,}{4,5,6}};  //合法,每行三个

              int a[2][3] = {{1,2,}{3,4,5,6}};  //合法,第一行最后一个默认为0

              int a[2][3] = {1,2,3,4,5,6,7};  //不合法,赋值的个数多余数组的个数

              int a[][3] = {1,2,3,4,5,6};    //不合法,不可以缺省行的个数

              int a[2][] = {1,2,3,4,5,6};    //合法,可以缺省列的个数

          使用: int a[10] = 0;

              1. a表示数组名,是第一个元素的地址,也就是元素a[0]的地址,等价于&a,查找元素直接a[1]/a[2]

              2. a是地址常量,因为a一直指向的是a[0]的地址,所以出现a++,或者是a=a+2赋值的都是错误的

              3. a是一维数组名,所以它是列指针,也就是说a+1是跳一列//二维数组是跳一行

        指针:指针变量是存储其他变量地址的变量

          指针举例:char *p,*q;

              p = "xyz";  //p并不等价于字符串"xyz",而是指向一个由xyz+四个字符组成的起始元素的指针

              q=p;    //把p赋值给q,只是复制这个指针并不复制指针指向的字符串,p,q指向的是同一块内存区域,即q,p的取值是相同的

              q[1] = 'y';  // &是取地址运算符,该操作符返回对象所在的内存地址 指针不能等同数组

            int *p,a[5] = {1,3,5,7,9,};最好分开定义,因为标识符是靠右结合的

            *p++:地址会变而值不变; (*p)++:是数值会变而地址不变, *p++:先执行++,再*取值,++的优先级更高

            *p++ = 3;因为本身数值为1,但是地址加1,所以移到3那里

            (*p)++ = 2;先取值再加1

            二级指针:只存放一级指针的地址

              指针的赋值与比较:在C++中指针变量的赋值和比较是基于指针变量的值,也就是说它所存储的地址,这样依赖,如果两个指针指向的是同一个对象,那么它们就是相等的

              如果指向不同的对象,那么即使指针变量指向的对象本身是相等的,指针变量也是不等的,举例,如果lhs和rhs是指针变量(兼容的类型),那么lhs = rhs 是使lhs指向rhs指向

              的同一个对象,数组事实上是一个指向内存的地址,而不是基本数组类型,对数组使用 = 的结果是复制两个指针的值,而不是复制整个数组

              ey:int x =7;

              int *p = &x,**q = p;

              答:*p = 7;*q=p;**q=7;

              简言之:int x = 7; int *p = &x, int **q = p;

              p = &x,推导出*p = 7;

      字符串赋值

        把s指针中的字符串复制到t指针中的方法

        1. while ((*t=*s)!=null) {  //完整版本

          s++;

          t++;

          }

        2. while(*t++ = *s++)    //高级版本 ++权限比*高,先执行++再执行*

      memset&memcpy  

        memcpy函数的用法 void *memcpy(void *dest, void *src,size_t n);

        函数的功能是从源src所指向的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中

        注意size_t是字节数,一般都是sizeof()形式

        1. 一般情况下dest的要大于src

        2. 计算size时计算src的大小,以便完整的取出src

        char *s="Golden Global View"; 

        char d[20];

        memcpy(d,s+14,4);//从第14个字符(V)开始复制,连续复制4个字符(View)

        //memcpy(d,s+14*sizeof(char),4*sizeof(char));//也可

        memset函数的用法 void *memset(void *s, int ch, size_t n);

        函数的功能是将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII码值,第一个值为指定的内存地址

        块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作,其返回值为指向s的指针,注意内存的相关事情

      机器数和真值,原码,反码和补码

        机器数:一个数在计算机中的二进制表示形式,叫做这个数的机器数,机器数是带符号的,在计算机中用一个数的最高位存放符号,正数为0,负数为1,

          例如:十进制中的+3,计算机中的字长为8位,转换成二进制即是00000011,如果是-3,则是10000011

        真值:机器数对应的真正数值就是机器数的真值  //原码,反码,补码的基础概念和计算方法,只有有符号数才有这三种码

        原码:符号位加上真值的绝对值,即用第一位表示符号,其余位表示值

          举例:拿1作为int型的八位来计算,一般情况下,int对于16位编译器来说就是16位

            [+1]原=0000 0001; [-1]原= 1000 0001

        反码:正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余各个位取反

            [+1]原=0000 0001; [+1]反= 0000 0001

            [-1]原=1000 0001; [-1]反= 1111 1110

        补码:正数的补码就是其本身,负数的补码是在其原码的基础上,符号位不变,其余各个位取反,最后加1(补码是在反码的基础上加1)

            [+1]原=0000 0001; [+1]补= 0000 0001

            [-1]原=1000 0001; [-1]补= 1111 1111

      文件指针&文件描述符

        文件指针:C语言中使用文件指针作为I/O的句柄,文件指针指向进程用户区中的一个被成为FILE结构的数据结构

          FILE结构包括一个缓冲区和一个文件描述符

        文件描述符:文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在windows系统上,文件描述符被称作文件句柄),在linux系统中打开文件就会获得

          文件描述符,它是个很小的正整数(一般在0-255),每个进程在PCB(Process Control Block)中保存着一份文件描述符表

          文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针

      内存泄露&内存损坏

        内存泄露:未释放不再使用的内存称为内存泄露

        内存损坏:释放或改写正在使用的内存称为内存损坏

      什么是不可移植的程序

        例如我们把int的值看做一个确定不变的已知值定义了一个变量,那么这种程序就是不可移植的,程序也应该避免这种依赖于实现环境的行为

        如果依赖于实现环境,那么在另一个环境下此int如果与之前定义变量不同,那么就会进行类型转换,就此会导致不可知行为,像qint16等类型即是为移植而生

      动态库文件与静态库文件

        动态库文件:动态库文件的扩展名是.so

        静态库文件的扩展名是.a(静态库文件很大,比动态库文件大的多)

          不论静态还是动态,都是由.o文件创建的,都以lib开头, 当静态库文件与动态库文件同名时gcc会优先使用动态库,在程序编译时会被链接到目标代码中,程序运行时

          不再需要该静态库文件,而动态库文件在程序编译时并不会链接到目标代码,而是在程序运行时才被载入,因此在程序运行时还需要动态库文件存在

      make的行为

        输入make进行编译时,make程序在当前目录寻找名为makefile的文件,该文件作为工程文件已经被建立,这个文件列出了源代码文件间的依赖关系,make程序观察文件的日期,

        如果一个依赖文件的日期比它所依赖的文件旧,make程序执行依赖关系之后列出的规则  //makefile文件中的所有注释都从"#"开始一直延续要本行的末尾

      库函数调用与系统调用

        库函数调用:在所有的ANSI C编译器版本中,C库函数是相同的;它调用函数库中的一个程序;与用户程序相联系;在用户地址空间执行;它的运行时间属于"用户时间"

          属于过程调用,开销较小;在C函数库libc中有大约300个程序

        系统调用:各个操作系统的系统调用是不同的;它调用系统内核的服务;是操作系统的一个进入点;在内核地址空间执行;它的运行时间属于"系统时间";需要在切换到内核

          上下文环境然后切换回来,开销较大;在UNIX中大约有90个系统调用

          函数调用速度:系统函数调用<库函数调用<普通函数调用

        编译预处理不是C语言的一部分,不占运行时间,不要加分号,C语言编译的程序称为源程序,它以ASCII码数值存放在文本文件中

  • 相关阅读:
    elasticsearch-搜索-定位搜索(十一)
    redis-缓存设计-自动延迟调度,最热商品缓存(二)
    20200925
    20175312 2018-2019-2 实验一《Java开发环境的熟悉》实验报告
    20175312 2018-2019-2 《Java程序设计》结对编程练习_四则运算(第一周:阶段性总结)
    20175312 2018-2019-2 《Java程序设计》第5周学习总结
    20175312陶光远 与 20175309刘雨恒 结对
    20175312 2018-2019-2 《Java程序设计》第4周学习总结
    20175312 2018-2019-2 《Java程序设计》第3周学习总结
    20175312 2018-2019-2 《Java程序设计》第2周学习总结
  • 原文地址:https://www.cnblogs.com/qianqiannian/p/6065098.html
Copyright © 2020-2023  润新知