学C语言第四天

不是什么文档,也不是教程,只是监督自己打卡学习C语言,记录的只是自己一些小笔记。如有错处,十分感谢您指出!!!

一、数组

  • 给数组中下标为二的元素开始赋值
  // C99
  char array_char[5] = {
    
    [2] = 'o', 'l', 'l'};
  for (int i = 0; i < 5; ++i) {
    
    
    PRINT_CHAR(array_char[i]);
  }

二、字符串

  • 字符串与字符数组还是有一定区别的。字符串是以\0结尾

三、函数的数组类型参数

  • 函数的参数是数组时候,需要传递一个参数为数组长度,传递二维数组的时候,要确定其中一维数组的长度

四、指针

#include <stdio.h>
int main() {
    
    
  int a;
  scanf("%d", &a);//111
  int *p = &a;
  return 0;
}

内存中每一个部分标了一个地址,以上面的案例为例
在这里插入图片描述

  • 首先图上可以得到p,&p,a,&a的内容
  • p内容里面是包含了a的地址,而&a也是a的地址(说的废话,哈哈哈)。这里为0x65fe14,在内存中查看这边区域的内容为
    在这里插入图片描述

这里是16进制,转成10进制就是我们输入的111

  • 这个时候取&p,也就是p所在的空间,取出来的为0x65fe18
    在这里插入图片描述

  • 那么按照我们之间学过的,内存编号为0x65fe18的区块包含的内容是0x65fe14(a的地址),结果证明确实如此,下图。
    在这里插入图片描述
    在这里插入图片描述

果然看理论是看不实在的,还是动手起来自己瞧一瞧来的实在与真实。

五、只读指针变量与只读变量指针

  • 记住const具有左结合性就好
  • 再记住一点*p是指向空间内容,p是空间本身

(1)当有

  int a;
  int b;
  //const修饰指针*,p的空间不能改变
  int * const p = &a;
  //p = &b;报错

(2)当有

  int a;
  int b;
  //const修饰int,p的内容不能变
  int const *p = &a;
  //*p = 11;报错

六、不能使用的指针

  • 不能够给指针随便定义一个地址,不能硬编码
  • NULL是一个宏,但是不要给NULL指针赋值
  • 杜绝野指针,例如用全局指针指向一个会被销毁的自动类型变量

七、特殊指针

  • 指针加减数字,其实是加减的指针指向内容的类型字节数的相应倍数,下面是案例
#include <stdio.h>
int main() {
    
    
  int a = 5;
  int *p = &a;
  //当前环境下int为4个字节
  printf("%d\n",sizeof(int));//4
  printf("%hx\n",p);//fe0c
  p += 1;
  printf("%hx\n",p);//fe10,刚好位移4个字节

  double b = 5.0;
  double *q = &b;
  //当前环境下double为8个字节
  printf("%d\n",sizeof(double));//8
  printf("%hx\n",q);//fe00
  q += 1;
  printf("%hx\n",q);//fe08,刚好8个字节
  return 0;
}
  • 数组也是一个指针,但是不能用来改变其空间,相当于一个 * const

八、左值与右值

  • 左值是内存的空间,右值是值
  • *p放在左边是空间,放在右边是值

九、动态内存分配

  • 需要引入标准库<stdlib.h>
  • malloc创建,free销毁
  • 记得初始化,避免脏数据
  • calloc会先直接清除为0
  • realloc是重新分配,但是追加的不会进行清空
  • 内存分配失败时候,返回空指针
  • free过后请NULL

十、常见指针使用错误

  • 忘记释放指针
  • 访问已经释放的指针
  • 使用超出边界
  • 改变内存的指针

十一、函数指针

  • 函数有地址,那么函数也有指针
  • 和数组一样,函数名其实就是函数的地址
  • 可以使用typedef定义函数类型
#include <stdio.h>
#include <stdlib.h>
#include <io_utils.h>

// 1
int *(f1(int, double));

// 2
int (*f2)(int, double);

// 3
int *(*f3)(int, double);

// 4
// int (*f4)(int, double)[];

// 5
// int (*f5)[](int, double);

typedef int (*Func)(int, double);

typedef int Boolean;
typedef int *IntPtr;
typedef int IntArray[];

int Add(int left, double right) {
    
    
  return (int) (left + right);
}

void InitPointer(int **ptr, int length, int default_value) {
    
    
  *ptr = malloc(sizeof(int) * length);
  for (int i = 0; i < length; ++i) {
    
    
    (*ptr)[i] = default_value;
  }
}

int main() {
    
    
  int a;
  IntPtr p;
  IntArray players = {
    
    1,3,4,5};
  PRINT_HEX(&main);
  PRINT_HEX(&InitPointer);

  void (*func)(int **ptr, int length, int default_value) = &InitPointer;

  func(&p, 10, 0);
  InitPointer(&p, 10, 0);

  (*func)(&p, 10, 0);
  (*InitPointer)(&p, 10, 0);


  PRINT_INT_ARRAY(p, 10);

  free(p);

  Func func1 = &Add;
  int result = func1(1, 3.0);
  PRINT_INT(result);
  return 0;
}

十二、乱七八糟

  • c99之后才支持可变长度,所以MSVC中不支持数组长度为一个变量,但是记住gcc做单独的扩展
  • c90的数组甚至是const只读属性也是不行的,必须要求使用常量
  • clion中使用ctrl+w查看运算符优先级

猜你喜欢

转载自blog.csdn.net/qq_45549336/article/details/112797015