• [啃书] 第2篇


    说在前面

    既然周末,就再来一篇吧,之后隔一天更一篇。

    本篇总结自《算法笔记》2.5-2.7

    正文

    知识点1:数组(一维)

    数据类型 数组名[数组大小]

    数组大小不能是变量,所以该定义要求定死了。

    数组初始化

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

    上方数组没有全部初始化,未初始化部分默认值为很大的随机数或0(看编译器不同赋值不同)。

    若完全不初始化如int a[10],数组中每个元素都可能是随机数,不一定默认为0。

    所以需要整个数组都赋初值为0,则只要把第一个赋为0即可,如int a[10] = {0};


    知识点2:冒泡排序

    总体说:进行n-1轮排序,忽略上一轮的最大值,每轮都把最大的“沉底”后移,其它的数像“冒泡”一样前移。

    具体说:

    比如5个数,从第1位第2位开始两两比较,前者大则交换,一直到第4位第5位比较算一轮,得到第5位为最大;

    继续下一轮两两比较不过到第3位和第4位比较完为止,因为第5位已经是最大值了;

    继续下一轮两两比较到第2位第3位为止,因为第4位也已经确定了;

    继续下一轮两两比较第1位第2位。

    程序员不知道这个就有点说不过去了,直接上代码吧


    知识点3:数组(二维)

    数据类型 数组名[第一维大小][第二维大小]

    数组初始化

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

    代码示例:两个数组对应值累加,存入第一个数组。

    输入两个3×3的矩阵,输出一个3×3的结果矩阵。

    注:如果数组长度过大超过106则将其定义在主函数外(静态存储区),否则在主函数中申明(系统栈)程序会异常退出。

    三维数组及更高维度的数组与二维类似,定义要三个[],赋值要三层循环。如int a[3][3][3];

    这一部分比较简单就不自己敲了,后面难的部分手打代码。


    知识点4:memset对数组每个元素赋相同值(需string.h头文件)

    memset(数组名, 值, sizeof(数组名));

    建议只赋值为0或-1(因为memset按字节赋值,组成int的四个字节会被赋成相同值,而0和-1的二进制补码全为0和1,不容易出错,如果赋别的数则会不准确,所以别的数用fill函数,后面会讲)

    memset速度快于fill


    知识点5:字符数组

    字符数组定义和初始化和普通数组一样

    char str[15] = {'G', 'o', 'o', 'd', '', 's', 't', 'o', 'r', 'y', '!'};

    也可以直接初始化字符串给字符数组(仅限初始化,其他地方赋值不行)

    char str[15] = "Good Story!"

    输入输出:

    scanf,getchar,gets

    printf,putchar,puts

    gets

    用来输入一行字符串;

    gets识别换行符 作为输入结束;

    若前面有整数等输入则要先使用getchar把换行符接受掉,再进行gets,否则读空了;

    存放于一维数组/二维数组的一维中;

    puts

    用来输出一行字符串;

    将一维数组/二维数组的一维输出在界面上(并拼上一个换行符);

    说明:二维字符数组可以当作字符串数组

    字符数组的存放方式

    一维字符数组/二维字符数组的二维末尾都有一个空字符表示存放字符串的结尾(作用是给puts和printf识别输出结束)

    特别注意1:

    的ASCII码为0即空字符NULL,占用一个字符位,因此开字符串数组要记得比字符串长度至少多1

    不是空格,空格的ASCII码是32,切勿混淆。

    特别注意2:

    scanf和gets输入的字符串自带,而getchar等其它方法得到的字符数组一定要自己在末尾加上否则乱码。


    知识点6:字符数组常用方法(string.h头文件)

    strlen(字符数组);

    返回第一个前字符的个数

    strcmp(字符数组1,字符数组2);

    返回两个字符串大小比较结果(字典序。正数:前者大,负数:前者小,零:一样大)

    strcpy(字符数组1,字符数组2);  

    2复制给1,包括也复制了

    strcat(字符数组1,字符数组2);

    2接到1后面


    知识点7:sscanf和sprintf(stdio.h)

    sscanf(str, "%d", &n);

    把字符数组str中的内容以%d的格式写到n中(从左到右)

    sprintf(str, "%d", n);

    把n以%d的格式写入到str字符数组中(从右到左)

    类比记忆:scanf相当于scanf(screen, "%d", &n)把屏幕内容输到n中,而sscanf则把screen变成了字符串,同样的类比printf。

    应用

    int n;
    double db; char str[100] = "2048:3.14,hello", str2[100] sscanf(str, "%d:%lf,%s", &n, &db, str2);
    //分别取到n=2048,db=3.14,str2=hello
    int n = 12;
    double db = 3.1415;
    char str[100], str2[100] = "good";
    sprintf(str, "%d:%.2f,%s", n, db, str2);
    //str得到12:3.14,good

    字符串处理问题的利器。 


    知识点8:函数

    返回类型 函数名称(参数类型 参数){
      函数主体
    }

    局部变量、形参只是实参的副本、int main()返回0在于告诉系统程序正常结束

    数组作为参数 void change(int a[], int b[][5]){ }

    函数的嵌套、递归


    知识点9:指针

    计算机中每个字节都有一个地址,指针可以理解为变量的地址。

    变量的地址一般是它占用的字节中第一个字节的地址(比如一个int占了四个字节,其中第一个字节的地址)

    对变量进行&取地址操作即可获得变量的地址。

    指针是一个unsigned类型的整数


    知识点10:指针变量

    用专门定义的类型来存放指针,

    int* p;
    double* p;
    char* p;
    int* p1, p2; //p1是int*型,p2是int型
    int *p1, *p2, *p3; //都是int*型
    int a; int* p = &a; //指针类型赋值
    int a; int* p; p = &a;//效果同上
    int a,b; int *p1 = &a, *p2 = &b;//多个指针变量初始化
    //星号可以跟着类型也可以贴着变量,除了多个定义时跟着变量,但具体是p存储了指针而不是*p
    //*p中的星号是找到p地址对应的变量,是一个对p的操作。
    //int* p中的星号则是和int构成一个int*指针类型,不是独立的。
    //所以为什么int* p更有利于理解而不是int *p
    //改变变量内容不影响地址

    对于int*型的指针变量p来说,p+1是指p所指的int型变量的下一个int型变量地址(跨越了一整个int型即4Byte,如果是double*型的指针变量p则跨越了一整个double型是8Byte)


    知识点11:指针与数组

    数组名称也作为数组的首地址使用,即 a==&a[0]

    *a表示数组第一个数

    *(a+1)表示数组第二个数(因为指针后移了再用星号取地址)

    *(a+i)表示数组第i-1个数

    示例代码:读取一整个数组并输出

    遍历数组(指针方法)

      

    指针的减法

     

    因为是int*型,所以距离以int为单位,输出5而不是20。


    知识点12:指针作函数参数

    #include<stdio.h>
    
    void change(int* p){
      *p = 233;
    }
    int main(){
      int a = 1;
      int* p = &a;
      change(p);
      printf("%d
    ", a);
      return 0;
    }

    输出结果:233

    传入了指针(p),通过指针把找到它所指向内容,把该内容(变量a)改变了。

    交换两个数(指针做参数)

    #include<stdio.h>
    
    void swap(int* a, int* b){
      int temp = *a; //temp是存放指针指向的内容的,所以是int型而不是int*型
      *a = *b;
      *b = temp;
    }
    
    int main(){
      int a = 1, b = 2;
      int *p1 = &a, *p2 = &b;
      swap(p1, p2);
      printf("a = %d, b = %d
    ", *p1, *p2);
      return 0;
    }

    常见错误1:int* temp没赋初值直接*temp = *a,错在没赋初值的指针可能会指向系统工作区。

    如果定义int* temp指针作为中间值,则使用*temp来暂存内容。

    则一定记得要指针变量要赋初值,写成如下

    常见错误2:int* temp直接暂存地址,把两个地址进行交换。

    错在传过来的指针类型(也就是变量的地址)是一个副本,我们现在拿到的是变量a,b的地址,所以我们可以去找到他们修改,就可以实现交换;而我们不知道地址的地址,即我们只知道地址的内容(副本),无法找到地址,也就无法修改地址,不能修改就无法交换地址。


     知识点13:引用

    给某变量起个别名,该别名同样能访问到这个变量。

    代替指针实现修改传入参数的功能,引用在实战中很常用。

    #include<stdio.h>
    
    void change(int &x){ //可以贴着int,也可贴着x(注意区分取地址符&)
      x=1;
    }
    
    int main(){
      int x = 10;
      change(x);
      printf("%d
    ", x);
      return 0;
    }

    输出结果:1

    应用:交换地址

    对指针的引用(对地址的引用,也就是给地址起个别名,可以直接访问到地址)

    #include<stdio.h>
    
    void swap(int* &p1, int* &p2){ //对int*型指针的引用
      int* temp = p1;
      p1 = p2;
      p2 = temp;
    }
    
    int main(){
      int a = 1, b = 2;
      int *p1 = &a, *p2 = &b;
      swap(p1, p2);
      printf("a = %d, b = %d
    ", *p1, *p2);
      return 0;
    }

    原理是因为,int*可以理解为unsigned int型,所以就像一个普通变量取地址一样,而这里的普通变量碰巧也是地址,也就是地址的地址。


    有点长了,分开再写一篇吧。

    第二章剩下结构体、补充内容及黑盒测试,下一篇继续。

    加油。

  • 相关阅读:
    【贪心+DFS】D. Field expansion
    【贪心+博弈】C. Naming Company
    【dp】E. Selling Souvenirs
    【multimap的应用】D. Array Division
    内存变量边界对齐
    3.8 高级检索方式(二)
    3.7 高级检索方式(一)
    openGL加载obj文件+绘制大脑表层+高亮染色
    3.6 Lucene基本检索+关键词高亮+分页
    3.5 实例讲解Lucene索引的结构设计
  • 原文地址:https://www.cnblogs.com/cc1997/p/12943864.html
Copyright © 2020-2023  润新知