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

指针的声明

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;
}
相关推荐
坚果派·白晓明3 小时前
鸿蒙 PC 应用集成 libhv 鸿蒙化三方库 —— AtomCode + Skills 驱动的高效集成实践
c语言·c++·ai编程·harmonyos·atomcode
aaaameliaaa3 小时前
C语言随机数函数使用全解析
c语言·笔记
玖玥拾5 小时前
C/C++ 数据结构(二)双向链表
c语言·数据结构·c++
dnbug Blog5 小时前
C 程序基本结构
c语言·程序结构
QiLinkOS5 小时前
极客精神与商业思维的融合实践(2)
c语言·c++·人工智能·算法·开源协议
不会C语言的男孩5 小时前
Linux 系统编程 · 第 2 章:系统调用与库函数
linux·c语言
Luminous.6 小时前
C语言--day29
c语言·开发语言
十月的皮皮7 小时前
C语言学习笔记20260612-菱形图案打印(两种写法)
c语言·笔记·学习
AI科技星7 小时前
第三卷:质数王朝志(全卷定稿)
c语言·开发语言·汇编·electron·概率论
2601_951645748 小时前
C语言基础语法,分支语句
c语言·运算符·if语句·switch语句·分支语句