定义一个指针,一定要malloc才可以使用,不然就是野指针,无法使用?

本文通过一个简单的C语言程序示例,展示了未正确初始化的指针(即野指针)在尝试使用时可能导致程序崩溃的情况,并对比了正确申请内存后的程序运行结果,强调了在C/C++中合理管理内存的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
   char *p=NULL;
//   p=(char *)malloc(sizeof(p));  //注明此处没有申请内存,野指针,会出现内存泄漏。
   strcpy(p,"abc");
   printf("%s\n",p);
   return 0;

}

farsight@ubuntu:~/malloc$ gcc pp.c
farsight@ubuntu:~/malloc$ ./a.out
Segmentation fault (core dumped)

farsight@ubuntu:~/malloc$ 


申请内存才可以使用

farsight@ubuntu:~/malloc$ vi pp.c
farsight@ubuntu:~/malloc$ gcc pp.c
farsight@ubuntu:~/malloc$ ./a.out
abc
farsight@ubuntu:~/malloc$ 


这是一个非常好的问题!你提到“为什么不定义一个指针”,我们来从**顺序表的实现方式**和**指针在C语言中的作用**两个方面来详细分析。 --- ## ✅ 一、你当前的顺序表实现方式 你当前定义的顺序表是这样的: ```c typedef struct Linklist { int data[20]; // 静态数组 int length; } seqlist; ``` 这是一个**静态顺序表**,即 `data` 是一个固定大小的数组(容量为20),它在结构体内部就已经分配好了空间。 你传递结构体时是这样做的: ```c void Creat(seqlist* p) { p->length = 0; } ``` 这已经使用了**指针传参**,目的是为了在函数中修改结构体的内容。 --- ## ✅ 二、你问的“为什么不定义一个指针”可能包含两个层面的理解: ### 🔹 1. **为什么不把结构体本身定义指针?** 比如: ```c seqlist* list = (seqlist*)malloc(sizeof(seqlist)); ``` 而不是: ```c seqlist list; Creat(&list); ``` ### ✅ 回答: 这是**静态分配**和**动态分配**的区别。 #### ✅ 静态分配(你现在的做法): ```c seqlist list; Creat(&list); ``` - 结构体变量 `list` 是在栈上分配内存; - 使用简单,适用于大小固定的结构体; - 不需要手动释放内存; - 缺点是不够灵活,不能扩展。 #### ✅ 动态分配(使用指针): ```c seqlist* list = (seqlist*)malloc(sizeof(seqlist)); Creat(list); ``` - 在堆上分配内存; - 更加灵活,适用于需要动态扩展或传递给多个函数的情况; - 需要手动调用 `free()` 释放内存; - 常用于链表、树、图等复杂结构中。 #### ✅ 总结: 你**可以定义一个指针**,但不是必须的。是否使用指针取决于你的使用场景: | 使用方式 | 是否使用指针 | 适用场景 | |----------|---------------|-----------| | 静态分配 | 不用指针 | 小型程序、教学示例、固定大小 | | 动态分配 | 使用指针 | 大型程序、需要动态扩展、模块化设计 | --- ### 🔹 2. **为什么不把 data 定义指针?** 你现在的结构体是: ```c int data[20]; ``` 为什么不写成: ```c int* data; ``` 然后动态分配内存? ### ✅ 回答: 这是**静态数组**和**动态数组**的区别。 #### ✅ 静态数组(你现在的做法): ```c int data[20]; ``` - 固定大小,最多只能存20个元素; - 简单易用; - 内存自动分配,无需手动释放; - 不够灵活,不能扩展容量。 #### ✅ 动态数组(使用指针): ```c int* data; ``` 然后在初始化时分配内存: ```c list->data = (int*)malloc(sizeof(int) * capacity); ``` - 可以根据需要调整容量; - 更加灵活,适合实际应用; - 需要手动管理内存(malloc/free); - 可以实现动态扩容(如插入时容量不够就 realloc)。 #### ✅ 示例代码(动态数组): ```c typedef struct { int* data; // 指向动态数组 int length; // 当前元素个数 int capacity; // 当前容量 } SeqList; void InitList(SeqList* list, int init_capacity) { list->data = (int*)malloc(sizeof(int) * init_capacity); list->length = 0; list->capacity = init_capacity; } void ExpandList(SeqList* list) { int new_capacity = list->capacity * 2; int* new_data = (int*)realloc(list->data, sizeof(int) * new_capacity); if (new_data != NULL) { list->data = new_data; list->capacity = new_capacity; printf("扩容成功,当前容量为:%d\n", new_capacity); } } ``` --- ## ✅ 总结:你“可以”定义指针,但“不一定必须” | 问题 | 回答 | |------|------| | 为什么不定义结构体指针? | 可以定义,但如果是局部使用,静态分配更简单 | | 为什么不把 data 定义指针? | 可以定义,但如果你只需要固定容量,静态数组更简单 | | 什么时候必须用指针? | 需要动态扩容、跨函数传参、避免拷贝、模块化设计时 | | 使用指针的好处是什么? | 灵活、节省栈空间、支持动态内存管理 | | 使用指针的风险是什么? | 容易造成内存泄漏、空指针访问、指针等 | ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值