指针Pointer
如果你爱编程,请你爱C语言; 如果你爱C语言,请你爱指针; 如果你爱指针,请你爱指针的指针!
毫无疑问,指针是C语言的灵魂。指针也成了一部分人不可逾越的坎
学好指针需要的条件:耐心,笔,纸 --> 画内存图
两个符号*和&
*
解地址
- 在定义变量时,
*
号表示所声明的变量为指针类型 - 在指针使用时,
*
号表示操作指针所指向的内存空间- 相当通过地址(指针变量的值)找到指针指向的内存,再操作内存
- 放在等号的左边赋值(给内存赋值,写内存)
- 放在等号的右边取值(从内存中取值,读内存)
&
取地址符号
- 取该变量的地址
pointer_demo.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
int a = 100;
int* p = NULL;
// 指针指向谁,就把谁的地址赋值给指针
p = &a;
//通过*可以找到指针指向的内存区域,操作还是内存
*p = 22;
printf("a = %d, *p = %d\n", a, *p);
// *放在=左边,给内存赋值,写内存
// *放在=右边,取内存的值,读内容
int b = *p;
printf("b = %d\n", b);
return 0;
}
pointer_demo1.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char* p = NULL;
char buf[] = "abcdef";
printf("p1 = %d\n", p);
// 改变指针变量的值
p = buf;
printf("p2 = %d\n", p);
//指针变量,和指向指向的内存是两个不同的概念
p = p + 1; //改变了指向变量的值,改变了指针的指向
printf("p2 = %d\n", p);
printf("buf = %s\n", buf);
printf("*p = %c\n", *p);
//改变指针指向的内存,并不会影响到指针的值
printf("改变指针指向的内存,并不会影响到指针的值\n");
buf[1] = '1';
printf("p3 = %d\n", p);
printf("buf2 = %s\n", buf);
*p = 'm';
printf("p4 = %d\n", p);
printf("buf3 = %s\n", buf);
return 0;
}
指针步长
指针加法:和指针类型相关
指针所指向的内存空间决定了指针的步长。数据类型一样,步长肯定一样,步长一样,不代表数据类型一样。
pointer_demo2.c
c
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
char ch;
char* p1 = &ch;
printf("p1:%ld, p1+1: %ld\n", p1, p1 + 1); //步长为1字节
int16_t a;
int16_t* p2 = &a;
printf("p2:%ld, p2+1: %ld\n", p2, p2 + 1); //步长为2字节
int32_t b;
int32_t* p3 = &b;
printf("p3:%ld, p3+1: %ld\n", p3, p3 + 1); //步长为4字节
int64_t c;
int64_t* p4 = &c;
printf("p4:%ld, p4+1: %ld\n", p4, p4 + 1); //步长为8字节
return 0;
}
二级指针
pointer_demo3.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int foo(char** pp) {
char* tmp = (char*)malloc(100);
strcpy(tmp, "ALGKJDLSJGLKDSJ");
*pp = tmp; //间接赋值
return 0;
}
int main(int argc, char* argv[]) {
char* p = NULL;
int ret = 0;
ret = foo(&p);
printf("p = %s\n", p);
free(p);
p = NULL;
return 0;
}
多级指针
指针和数组
数组名的值是一个指针常量,也就是数组第一个元素的地址
*
和[]
关系
数组指针和指针数组
数组指针:是一个指针,指向数组的指针
指针数组:是一个数组,数组内容是指针
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[]) {
// 1.指针数组
char* pointer_arr[] = {"hello", "world", "您好", "世界"};
// 2.数组指针
int arr[] = {100, 300, 400, 400};
int(*arr_pointer)[] = &arr; // 数组指针
// (*arr_pointer); // 数组
// (*arr_pointer)[index]; // 元素
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
printf("%d -> %d\n", i, (*arr_pointer)[i]);
}
return 0;
}
内存图:
指针和字符串
指针和结构体
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct persion {
char name[64];
int age;
};
// 结构体里面套一级指针
struct persion_s {
char* name;
int age;
};
// 结构体里面套二级指针
struct persion_ss {
char** name;
int age;
};
int main(int argc, char* argv[]) {
// 1.普通
// struct persion p = {"shibin", 18};
// 2.结构体里面套一级指针
struct persion_s p;
p.name = (char*)malloc(64);
char* name = "shibin";
strncpy(p.name, name, strlen(name));
p.age = 18;
printf("p.name = %s; p.age = %d\n", p.name, p.age);
// 3.结构体里面套二级指针
struct persion_ss pp;
char* name_ss = (char*)malloc(64);
strncpy(name_ss, name, strlen(name));
pp.name = &name_ss;
pp.age = 18;
printf("pp.name = %s; pp.age = %d\n", *pp.name, pp.age);
return 0;
}
结构体资源释放问题:
释放顺序:由内向外
struct_and_pointer_demo1.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 释放顺序
struct persion_s {
char** name;
int age;
};
int main(int argc, char* argv[]) {
char* name = "shibin";
struct persion_s* p = malloc(sizeof(struct persion_s));
char* name_s = (char*)malloc(64);
strncpy(name_s, name, strlen(name));
p->name = &name_s;
p->age = 18;
printf("p.name = %s; p.age = %d\n", *(p->name), p->age);
// release
// 1.free name
free(*(p->name));
// 2.free struct persion
free(p);
return 0;
}
浅拷贝/深拷贝
copy_demo.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct persion_s {
char* name;
int age;
};
// 浅拷贝
void foo(void) {
char* name = "shibin";
struct persion_s shi;
shi.name = (char*)malloc(64);
strncpy(shi.name, name, strlen(name));
shi.age = 18;
struct persion_s xiaoshi = shi;
printf("xiaoshi.name = %s; xiaoshi.age = %d\n", xiaoshi.name, xiaoshi.age);
// 内存图
}
// 深拷贝
void bar(void) {
char* name = "shibin";
struct persion_s shi;
shi.name = (char*)malloc(64);
strncpy(shi.name, name, strlen(name));
shi.age = 18;
struct persion_s xiaoshi = shi;
xiaoshi.name = (char*)malloc(64);
strncpy(xiaoshi.name, shi.name, strlen(shi.name));
printf("xiaoshi.name = %s; xiaoshi.age = %d\n", xiaoshi.name, xiaoshi.age);
}
int main(int argc, char* argv[]) {
// foo();
bar();
return 0;
}
内存图
函数指针
顾名思义:指向函数的指针
函数指针基本定义与使用
function_pointer_demo.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int add(int a, int b) {
return a + b;
}
int division(int a, int b) {
return a / b;
}
// 声明函数指针的类型
typedef int function(int a, int b); // 函数类型
typedef int (*function_t)(int a, int b); // 函数指针类型
typedef int (*function_arr_t[])(int a, int b); // 函数指针数组
int main(int argc, char* argv[]) {
int a = 100;
int* p = &a; // 普通变量 指针
// 1.函数指针
function* f = add;
int ret = f(10, 10);
printf("ret = %d\n", ret);
// 2.改进版本
function_t ff = add;
ret = ff(20, 20);
printf("ret = %d\n", ret);
// 3.函数指针数组
printf("\n");
function_arr_t fff = {add, division};
int len = sizeof(fff) / sizeof(fff[0]);
for (int i = 0; i < len; i++) {
if (fff[i] != NULL) {
ret = fff[i](100, 10);
printf("array: ret = %d\n", ret);
}
}
return 0;
}
函数指针作为函数参数:
function_pointer_as_arg_demo.c
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 函数指针作为参数
int add(int a, int b) {
return a + b;
}
// 声明函数指针的类型
typedef int function(int a, int b); // 函数类型
typedef int (*function_t)(int a, int b); // 函数指针类型
typedef int (*function_arr_t[])(int a, int b); // 函数指针数组
// int foo(int (*fun)(int a, int b)) {// 1.普通版本
int foo(function_t fun) { // 2.改进版本
int ret = fun(100, 100);
return ret;
}
int main(int argc, char* argv[]) {
int ret = foo(add);
printf("ret = %d\n", ret);
return 0;
}
指针的特性:
通过地址,获取/操作所指向的内容
指针的作用:
- 希望别人来修改我的值(内容),把地址给别人
- 作为传参,减少copy量.指针数据量小
- 调用函数:函数指针
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 1111111111
void foo(int* a) {
*a = 1000;
}
// 2222222222
void bar(const char* str) {
printf("str = %s\n", str);
}
// 3333333333
typedef int (*function_t)(int a, int b);
int add(int a, int b) {
return a + b;
}
int foobar(function_t fun) {
int ret = fun(100, 100);
return ret;
}
int main(int argc, char* argv[]) {
// 1.让其它函数改变这个值
int a = 100;
foo(&a);
// 2.传参数的时候减少copy数据量
char* str = "hello world";
bar(str);
// 3.调用函数:函数指针
int ret = foobar(add);
printf("ret = %d\n", ret);
return 0;
}