指针,结构体,动态内存分配

指针的声明

c 复制代码
int a;
int *p
//星号两边的空格无关紧要,下面的声明是等价的
int* p;
int *p;
int * p;
int*p;

例如

c 复制代码
int main(int argc, char const* argv[]) {
	int a = 5;
	int* p;
	p = &a;
	printf("%p\n", &a);
	printf("%p\n", p);
	printf("%p\n", &p);
	return 0;
}

输出

c 复制代码
000000AD41CFFCF4
000000AD41CFFCF4
000000AD41CFFD18

*p解引用指针

c 复制代码
int main(int argc, char const* argv[]) {
	int a = 5;
	int* p = &a;
	printf("%d\n", *p);
	*p = 100;
	printf("%d\n", *p);
	return 0;
}

输出

c 复制代码
5
100

指针和数组

c 复制代码
int main(int argc, char const* argv[]) {
	int a[] = {15,22,67,43,87};
	int* p;
	p = a;
	printf("%p\n", a);
	printf("%p\n", p);
	printf("%d\n", *p);
	return 0;
}
c 复制代码
000000F81F2FF5B8
000000F81F2FF5B8
15

当把某个数组的地址赋给指针时候,存入的是数组的首地址的值

c 复制代码
int main(int argc, char const* argv[]) {
	int a[] = {15,22,67,43,87};
	int* p;
	p = a;
	for (int i = 0; i < sizeof(a) / sizeof(a[0]);i++){
		printf("%d\n", a[i]);
	}
	printf("\n");
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
		printf("%d\n", *(p+i));
	}
	return 0;
}
c 复制代码
15
22
67
43
87

15
22
67
43
87

当给指针加上一个整数的时候,实际上加的是这个整数和指针数据类型的对应的字节数的乘积

c 复制代码
p++
p = p + 1
p = p + 1×4
c 复制代码
int main(int argc, char const* argv[]) {
	int a = 5;
	int* p;
	p = &a;
		printf("%p\n", p);
		p++;
	printf("%p\n", p);
	return 0;
}
c 复制代码
000000F2612FFC84
000000F2612FFC88

指针与函数

c 复制代码
void swap(int* a, int* b) {
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
void swap1(int a, int b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}

void swap2(int *a, int *b) {
	int *temp;
	temp = a;
	a = b;
	b = temp;
}
int main(int argc, char const* argv[]) {
	int a = 5;
	int b = 10;
	swap1(a, b);
	printf("%d  %d\n", a, b);

	swap2(&a, &b);
	printf("%d  %d\n", a, b);

	swap(&a, &b);
	printf("%d  %d\n", a, b);
	return 0;
}
c 复制代码
5  10
5  10
10  5

swap1(值传递):交换的是变量副本 → 无效

swap2(指针传递):交换的是指针本身 → 无效

swap(正确写法):传地址 + 解引用 → 交换变量原始值 → 有效

结构体

相当于自己造一个数据类型

c 复制代码
#include<stdio.h>
#include<string.h>
struct student {
	char stuId[20];
	char stuName[20];
	char sex;
	char hometown[20];
	char major[30];
};

int main(int argc, char const* argv[]) {
	int a;
	struct student b;
	strcpy(b.stuId, "20389488");
	strcpy(b.stuName , "小明");
	strcpy(b.hometown , "中国");
	strcpy(b.major, "核物理");
	b.sex = '1';
	printf("%s,%s,%c,%s,%s\n", b.stuId, b.stuName, b.sex, b.major, b.hometown);
	return 0;
}
c 复制代码
20389488,小明,1,核物理,中国

比如从数据库中读取了n个学生数据,把这些数据分别存进这个student数据类型中,然后每一个变量里面都带着这些人的信息了

c 复制代码
#include<stdio.h>
#include<string.h>
struct student {
	char stuId[20];
	char stuName[20];
	char sex;
	char hometown[20];
	char major[30];
};

int main(int argc, char const* argv[]) {
	int a;
	struct student b[4];
	strcpy(b[0].stuId, "20389488");
	strcpy(b[0].stuName, "小康");
	strcpy(b[0].hometown, "中国");
	strcpy(b[0].major, "核物理");
	b[0].sex = '1';

	strcpy(b[1].stuId, "20389488");
	strcpy(b[1].stuName, "小名");
	strcpy(b[1].hometown, "中国");
	strcpy(b[1].major, "核物理");
	b[0].sex = '1';

	strcpy(b[2].stuId, "20389488");
	strcpy(b[2].stuName, "小化");
	strcpy(b[2].hometown, "中国");
	strcpy(b[2].major, "核物理");
	b[0].sex = '1';

	strcpy(b[3].stuId, "20389488");
	strcpy(b[3].stuName, "小四");
	strcpy(b[3].hometown, "中国");
	strcpy(b[3].major, "核物理");
	b[0].sex = '1';

	for (int i = 0; i < 4; i++) {
		printf("%s,%s,%c,%s,%s\n", b[i].stuId, b[i].stuName, b[i].sex, b[i].major, b[i].hometown);
	}
	return 0;
}
c 复制代码
20389488,小康,1,核物理,中国
20389488,小名,1,核物理,中国
20389488,小化,1,核物理,中国
20389488,小四,1,核物理,中国

类型定义

c 复制代码
typedef struct {
	char stuId[20];
	char stuName[20];
	char sex;
	char hometown[20];
	char major[30];
}student;//给结构体起别名叫student

int main(int argc, char const* argv[]) {
	int a;
	student b;//这里就不用struct student b,直接就可以省去struct
	strcpy(b.stuId, "20389488");
	strcpy(b.stuName, "小康");
	strcpy(b.hometown, "中国");
	strcpy(b.major, "核物理");
	b.sex = '1';
	printf("%s,%s,%c,%s,%s\n", b.stuId, b.stuName, b.sex, b.major, b.hometown);
	return 0;
}

结构体指针

c 复制代码
typedef struct {
	char stuId[20];
	char stuName[20];
	char sex;
}student;//给结构体起别名叫student

void initialStu(student* p) {
	strcpy((*p).stuId, "20389488");
	strcpy((*p).stuName, "小康");
	(*p).sex = '1';
}
int main(int argc, char const* argv[]) {
	student b;
	initialStu(&b);
	printf("%s,%s,%c\n", b.stuId, b.stuName, b.sex);
	return 0;
}
c 复制代码
20389488,小康,1

传递参数这个事,为什么喜欢传指针而不去传结构体本身,传的是&s而不是s,这里是有一个内存空间节省的事

结构体 s = 一整本厚厚的书(里面有很多数据:名字、年龄、学号、成绩......)

传结构体本身 s = 把整本书复印一遍,把复印件递给函数

传结构体指针 &s = 只告诉函数:这本书放在【0x123456】这个位置

函数会完整拷贝一份结构体的所有数据,放到函数的栈内存中。

结构体越大,拷贝占用的内存越多!

例:一个学生结构体

c 复制代码
struct Student {
    char name[20];  // 20字节
    int age;        // 4字节
    int id;         // 4字节
    float score;    // 4字节
};

这个结构体总大小 = 32 字节,传值就要拷贝 32 字节到函数里。

如果是嵌套数组、大结构体(比如 1024 字节),传值就要拷贝 1024 字节!(当然这里结构体可能不是32字节,因为有一个叫内存对齐,可能不止32字节)

传指针(传地址 &s)

无论结构体多大,只传递一个「内存地址」:

32 位系统:地址占 4 字节

64 位系统:地址占 8 字节

哪怕结构体是 1MB、1GB,传指针永远只占 4/8 字节!

原因是:

内存拷贝是需要CPU 耗时的:

传结构体本身:CPU 要逐字节复制整个结构体,数据越大越慢;

传指针:CPU 只需要复制一个地址,瞬间完成。

如果函数被频繁调用(比如循环 10000 次),传值会让程序明显卡顿,传指针几乎无性能损耗

函数的栈空间是有限的(一般只有几 MB),如果传一个超大结构体(比如嵌套了大数组):

传值拷贝 → 瞬间占满栈空间 → 程序直接崩溃(栈溢出);

传指针 → 仅占 8 字节 → 永远不会栈溢出。

代码对比:

c 复制代码
#include <stdio.h>
struct Student { char name[20]; int age; };

// 1. 传结构体本身(传值:拷贝整个结构体,费内存、改不动原数据)
void fun1(struct Student s) {
    s.age = 20;  // 改的是副本!
}

// 2. 传结构体指针(传地址:仅8字节,省内存、直接改原数据)
void fun2(struct Student *s) {
    s->age = 20; // 改的是原件!
}

int main() {
    struct Student s = {"张三", 18};
    
    fun1(s);   // 拷贝32字节,原age还是18
    fun2(&s);  // 拷贝8字节,原age变成20
    
    printf("%d", s.age); // 输出 20
    return 0;
}
相关推荐
Escalating_xu11 小时前
【C 语言】数据在内存中的存储:补码、大小端、整型陷阱与 IEEE 754 全解析
java·c语言·网络
神仙别闹19 小时前
基于C语言开发的捕捉流星小游戏
c语言·开发语言
水饺编程20 小时前
第1章,[Win32 章节]:API 及 内存管理模式
c语言·c++·windows·visual studio
Logic10120 小时前
C语言/数据结构位运算题解:异或XOR找出优秀项目组中的“独特编号“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
彦21 小时前
C和C++笔记
c语言·c++·笔记
Code_Solitude1 天前
反码,补码,原码
c语言
FLJwu1 天前
运动相机按键与连接器硬件选型实战02:USB‑C接口选型|防水失效、虚接断连、腐蚀烧口量产大坑
c语言·开发语言·经验分享·数码相机·相机·运动相机·oem 量产
Zw-awa1 天前
陀螺小车传奇之00011000
c语言·stm32
万年咸鱼1 天前
C语言内功心法篇——变量与数据类型
c语言·jvm·算法
Escalating_xu2 天前
【C 语言】深入理解指针(5):sizeof、strlen、数组名语义与指针笔试题全解析
java·c语言·开发语言