定义

指针0-255是系统保留的,不能读也不能写,NULL是指向0的
image.png
无论什么类型的指针,存的都是地址
内存地址都是无符号整形的,所以都是4个字节大小
10是四个字节
int* 表示我如果要改的话,对应那边数据的四个字节
char* 的话那就是对应那边数据的1个字节
指针里面只是地址,指针也是个变量

  1. int main(int argc, char *argv[])
  2. {
  3. int a = 10;
  4. int b = 100;
  5. //指针是一种数据类型,p是指针类型变量用来指向一个变量的地址
  6. int * p = &a;
  7. p = &b;
  8. printf("%p\n", &b); //001CF878
  9. printf("%X\n", p); //1CF878
  10. //通过指针修改变量的值
  11. *p = 200;
  12. printf("%d\n", b); //200
  13. printf("%d\n", *p); //200
  14. //sizeof()指针类型在内存中的大小,所有指针在32位是4个字节大小
  15. //按照unsigned int为每一个内存分配编号 2的32次方-1 所以32位操作系统最多用4g内存, 64位显示是8
  16. printf("%d\n", sizeof(p)); //4
  17. printf("%d\n", sizeof(int *)); //4
  18. printf("%d\n", sizeof(char *)); //4
  19. system("pause");
  20. return EXIT_SUCCESS;
  21. }

万能指针指定类型

  1. int main(int argc, char *argv[])
  2. {
  3. int a = 10;
  4. //指针里面存的是首地址
  5. void * p = &a;
  6. //转成指定类型,如果是char就转成char
  7. *(int *)p = 100;
  8. printf("%d\n", a); //100
  9. printf("%d\n", *(int *)p); //100
  10. system("pause");
  11. return EXIT_SUCCESS;
  12. }

如果是数组

  1. int main(int argc, char *argv[])
  2. {
  3. int arr[10];
  4. //首地址
  5. void * p = arr;
  6. //改变首地址的值也就是arr[0]
  7. *(int *)p = 100;
  8. //改变arr[1],因为里面存的是int,每个元素占用4个字节,但是已经转为int了,int+1就过了4个字节
  9. *((int *)p + 1) = 200; //就是arr[1]
  10. for (int i = 0; i < 10; i++)
  11. {
  12. printf("%d\n", arr[i]);
  13. }
  14. system("pause");
  15. return EXIT_SUCCESS;
  16. }

const

int * p
int *是指针的指向
p是指针的地址值

const修饰指针

const修饰变量是可以被修改的

  1. int main()
  2. {
  3. //这种方式不安全,可以通过指针修改
  4. const int a = 10;
  5. printf("%d\n", a);
  6. int * p = &a;
  7. *p = 100;
  8. printf("%d\n", a);
  9. printf("%d\n", *p);
  10. getchar();
  11. return EXIT_SUCCESS;
  12. }

建议用define

  1. #define LVL 100

const修饰指针类型

  1. int main()
  2. {
  3. int a = 10;
  4. int b = 20;
  5. //如果const修饰int * 不能改变指针变量指向的内存地址的值
  6. //但是可以改变指针存的地址
  7. const int * p;
  8. p = &a;
  9. p = &b;
  10. printf("%d\n", *p);
  11. getchar();
  12. return EXIT_SUCCESS;
  13. }

const修饰指针变量

  1. int main()
  2. {
  3. int a = 10;
  4. int b = 20;
  5. //const修饰指针变量
  6. int * const p = &a;
  7. //能改变指针变量指向地址的值,但不能改变指针指向的地址
  8. *p = 100;
  9. printf("%d\n", *p);
  10. getchar();
  11. return EXIT_SUCCESS;
  12. }

const同时修饰指针类型和指针变量

  1. int main()
  2. {
  3. int a = 10;
  4. int b = 20;
  5. //const修饰指针类型并且指针变量,那么都不能改变
  6. const int * const p = &a;
  7. getchar();
  8. return EXIT_SUCCESS;
  9. }

const和非const类型转换

当一个指针变量 str1 被 const 限制时,并且类似const char *str1这种形式,说明指针指向的数据不能被修改;如果将 str1 赋值给另外一个未被 const 修饰的指针变量 str2,就有可能发生危险。因为通过 str1 不能修改数据,而赋值后通过 str2 能够修改数据了,意义发生了转变,所以编译器不提倡这种行为,会给出错误或警告。
也就是说,const char *char *是不同的类型,不能将const char *类型的数据赋值给char *类型的变量。但反过来是可以的,编译器允许将char *类型的数据赋值给const char *类型的变量。
这种限制很容易理解,char *指向的数据有读取和写入权限,而const char *指向的数据只有读取权限,降低数据的权限不会带来任何问题,但提升数据的权限就有可能发生危险。
C语言标准库中很多函数的参数都被 const 限制了,但我们在以前的编码过程中并没有注意这个问题,经常将非 const 类型的数据传递给 const 类型的形参,这样做从未引发任何副作用,原因就是上面讲到的,将非 const 类型转换为 const 类型是允许的

指针和数组

指针遍历数组

int main()
{
    //数组名是数组的首地址,这是个常量
    int arr[10] = { 0 };
    //指向数组的指针,当操作指针的时候,间接操作了数组
    int* p = arr;
    for (int i = 0; i < 10; ++i) {
//        printf("%d\n", p[i]);
        //这样也可以
        printf("%d\n", *(p+i));
    }
    getchar();
    return EXIT_SUCCESS;
}

指针操作数组

int main() {
    //数组名是数组的首地址,这是个常量
    int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    //指向数组的指针,当操作指针的时候,间接操作了数组
    int *p = arr;
    //指针操作数组
    *p = 100;
    *(p + 1) = 200;
    p[5] = 300;
    *(p + 3) = 700;
    for (int i = 0; i < 10; ++i) {
//        printf("%d\n", p[i]);
        //这样也可以
        printf("%d\n", *(p + i));
    }
    getchar();
    return EXIT_SUCCESS;
}

多级指针

int main() {
    int a = 10;
    int* p = &a;
    int** pp = &p;
    int*** ppp = &pp;
    //所以  ***ppp = a
    getchar();
    return EXIT_SUCCESS;
}

image.png

字符常量

int main() {
    //字符数组,创建位置在栈区
    char arr[] = "hello world";
    //字符串常量,会在程序运行时,常量区,不能被修改的
//    char * arr = "hello world";
    printf("%p\n", arr);
    printf("%s\n", arr);
    getchar();
    return EXIT_SUCCESS;
}