Skip to content

Latest commit

 

History

History
423 lines (361 loc) · 10.1 KB

l_03.md

File metadata and controls

423 lines (361 loc) · 10.1 KB

本课有B站视频讲解 link

Lesson 3



1.地址

0x001 0x002 0x003 0x004 0x005 ..... 0xFFF
低地址 > > > > > 高地址

& 获取变量在内存中的首地址

grammar

&变量名

2. 指针

  • 指针的定义和使用 建议形式: 基类型* 变量名 = 变量地址;

    • 指针要赋初值
      int a = 10;
      int* p = &a;
      int* p int * p int *p int*p 都表示定义指针 但是请按照建议形式定义
    • 多个指针可以指向一个地址
      int *p1 = &a;
      int* p2 = &a;
      int* p3 = &a;
    • 指针类型可以强制转换
      double a = 20.0;
      int* p = (double*)&a;    
    • 指针占用内存
      int lengthInt = sizeof(int*);
      int lengthDouble = sizeof(double*);
      int lengthChar = sizeof(char*);
      int lengthBool = sizeof(bool*);
      所有变量类型的指针占用内存在64位系统中都为8,32位系统中位4
    • 解引用 * 运算符的优先级较低,注意加括号
      int a = 10;
      int* p = &a;
      printf("%d", *p); // 10
  • 空指针和野指针
    空指针:指针变量指向内存中编号为0的空间

    #define NULL ((void *)0)

    可用于初始化指针变量 但是空指针指向的内存是不可以访问的

    int* p = NULL;

    野指针:指针变量指向非法的内存空间
    0-255内存编号是系统占用的,不可以访问
    在程序中尽量避免出现野指针

    int* p = 0x001; // error
  • const 修饰指针

    • 指针常量 指针为常量 指针不可修改
      int a = 10;
      int b = 10;
      int* const p = &a;
      
      *p = 10;
      p = &b; // error
    • 常量指针 指向常量的指针 指针指向的值不可修改
      int a = 10;
      int b = 10;
      const int* p = &a;
      // or
      int const* p = &a;
      
      *p = 10; // error
      p = &b;
    • 常指针常量 指针地址和指向的值都不可修改
      int a = 10;
      int b = 10;
      const int* const p = &a;
      
      *p = 10; // error
      p = &b;  // error

3. 指针和函数

  • 地址传递 可以改变形参的值

    void swap(int* a, int* b) {
       // 对解引用值进行操作 而不是对指针变量进行操作
      int tmp = *a;
      *a = *b;
      *b = tmp;
    }
    
    int main() {
      int a = 10;
      int b = 20;
      swap(&a, &b);
      printf("a = %d, b = %d", a, b); // a = 20, b = 10
    }
  • 指针作为形参返回多个值

    void add(int* a, int* b) {
      (*a)++;
      (*b)++;
    }
    
    int main() {
       int a = 10;
       int b = 10;
       add(&a, &b);
       printf("a = %d, b = %d", a, b);  // a = 11, b = 21
       return 0;
    }
  • void 关键字

    只关心地址本身,不关心里面内容,用 void* 可以存放任意类型的地址

    void function(void* p) {
      printf("the var's address is %p\n", p);
    }
    
    int main() {
      int a = 10;
      function(&a);  // the var's address is 0x.....
      return 0;
    } 

    note:

    1. 不能用void声明变量
    2. 不能对void*直接解引用,需要转换成其他类型指针
    3. 把其他类型指针赋值给void*指针不需要转换
    4. void*指针赋值给其他指针需要转换
  • 返回指针的函数 int* function(int* a) {return a}

    int* function(int a){
      int* p = &a;
      return p;
    }
  • 函数指针 返回值类型 (*指针变量名) (参数表);

    void function(int x) {
      printf("%d", x);
    }
    int main(){
      int (*pFunction) (int x);
      pFunction = function; // pFunction指向function
      *pFunction(10); // 10
    }
  • 回调函数

4. 指针和数组

  • 一维数组 数组名为数组首地址 是一个指针常量

    数组元素地址表示 数组 arr[5] 数组元素表示
    arr or &arr[0] arr[0] arr[0] or *arr
    arr + 1 or &arr[1] arr[1] arr[1] or *(arr + 1)
    arr + 2 or &arr[2] arr[2] arr[2] or *(arr + 2)
    arr + 3 or &arr[3] arr[3] arr[3] or *(arr + 3)
    arr + 4 or &arr[4] arr[4] arr[4] or *(arr + 4)
    数组相邻元素地址差值 = 基类型占用内存大小
  • 二维数组

    • 二维数组 a[2][3] 在内存中的存储形式

      a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
    • 二维数组 a[2][3] 直观表示

      0 1 2
      0 a[0][0] a[0][1] a[0][2]
      1 a[1][0] a[1][1] a[1][2]
  • 二维数组的本质是行指针数组

    arr
    arr[0] -> arr[0][0] arr[0][1] arr[0][2]
    arr[1] -> arr[1][0] arr[1][1] arr[1][2]
  • 指针数组

    变量类型* 指针变量名[数组长度]

    int a[3][2];
    int* p[3];
    for(int i = 0; i < 3; i++){
        p[i] = a[i];
    }
    数组地址 p[3] 数组元素 指针指向
    p p[0] = a[0] a[0][0]
    &p[1] or p + 1 p[1] = a[1] a[1][0]
    &p[2] or p + 2 p[2] = a[2] a[2][0]

    数组相邻元素地址差值 = 指针占用内存大小

    详见案例

###5. 指针&数组&函数

  • 一维数组和函数

    int a[10];
    // 两种写法等价
    void func(int* a);
    void func(int a[]);
  • 行指针 / 数组指针 变量类型 (*指针变量名)[每行长度]

    int a[3][2];
    int (*p)[2];
    p = a;
    数组地址 (*p)[3] 数组元素 指针指向
    p a[0] a[0][0]
    &p[1] or p + 1 a[1] a[1][0]
    &p[2] or p + 2 a[2] a[2][0]

    数组相邻元素地址差值 = 基类型占用内存大小,即一维数组所占内存

    • 行指针指向一定长度的数组首地址 类型为 void[]* ,基类型为 void[][]

    • 行指针解决二维数组传参

      //两种写法等价
      void func(int (*p)[2]);
      void func(int p[][2]);

      详见案例


案例1 指针访问数组

  • 指针访问一维数组
void for_each(int arr[], int len) {
   for (int i = 0; i < len; i++) {
      printf("%d ", *(arr + i));
      //or
      printf("%d ", arr[i]);
   }
}

int main() {
   int a[5] = {1, 2, 3, 4, 5};
   int len = sizeof(a) / sizeof(int);
   for_each(a, len);
   return 0;
}
  • 指针数组访问二维数组
int main() {
   int a[3][2] = {1, 2, 3, 4, 5, 6};
   int* p[3];
   for (int i = 0; i < 3; i++) {
      p[i] = a[i];
      for (int j = 0; j < 2; j++) {
         printf("%d", *(p[i] + j));
      }
      printf("\n");
   }
   return 0;
}
  • 行指针访问二维数组
int main() {
   int a[3][2] = {1, 2, 3, 4, 5, 6};
   int(*p)[2];
   p = a;  // 行指针p等价与二维数组名a
   for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 2; j++) {
         printf("%d", *(p[i] + j));
         // or
         printf("%d", p[i][j]);
      }
      printf("\n");
   }
   return 0;
}
  • 行指针解决二维数组传参
void for_each(int arr[][2], int len) {
   for (int i = 0; i < 2; i++) {
      for (int j = 0; j < len; j++) {
         printf("%d", *(arr[i] + j));
         // or
         printf("%d ", arr[i][j]);
      }
      printf("\n");
   }
}

int main() {
   int a[3][2] = {1, 2, 3, 4, 5, 6};
   int len = sizeof(a) / sizeof(int[2]);
   for_each(a, len);
   return 0;
}

案例2 用函数编写五只小猪称体重问题

void function(int arr[], int len, int* max, int* min) {
   for (int i = 0; i < len; i++) {
      if (*(arr + i) > *max) {
         *max = *(arr + i);
      }
   }
   for (int i = 0; i < len; i++) {
      if (*(arr + i) <= *min) {
         *min = *(arr + i);
      }
   }
}

int main() {
   int a[5] = {300, 350, 200, 400, 250};
   int len = sizeof(a) / sizeof(int);
   int max = 0, min = 1000;
   function(a, len, &max, &min);
   printf("%d %d", max, min);
   return 0;
}

案例3 用函数编写冒泡排序算法

void bubbleSort(int* arr, int len) {
   for (int i = 0; i < len - 1; i++) {
      for (int j = 0; j < len - i - 1; j++) {
         if (arr[j] > arr[j + 1]) {
            int tmp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = tmp;
         }
      }
   }
}

void printArr(int arr[], int len) {
   for (int i = 0; i < len; i++) {
      printf("%d ", arr[i]);
   }
   printf("\n");
}

int main() {
   int a[5] = {300, 350, 200, 400, 250};
   int len = sizeof(a) / sizeof(int);
   bubbleSort(a, len);
   printArr(a, len);

   return 0;
}