指向堆区空间的指针

堆区空间的申请和释放(malloc,free)
#include <stdlib.h>
void *malloc(size_t size);
功能:在堆区申请给定的size字节的大小空间,并将该空间的地址返回给调用函数
参数:要申请的空间大小,以字节为单位
返回值:成功返回申请出来的空间的起始地址,是一个万能指针,使用时需要转变成具体的指针,失败返回NULL
void free(void *ptr);
功能:将堆区的手动申请的内存空间释放
参数:堆区空间的指针
返回值:无
3.可以完成单个空间的申请和释放也可以完成连续空间的申请和释放
#include<stdio.h>
#include<stdlib.h> //标准的库函数头文件
int main(int argc, const char *argv[])
{
//申请一个字节的空间
char *ptr1 = (char *)malloc(1); //malloc(sizeof(char)) //在堆区申请1字节的空间,并将地址赋值给ptr1
if(ptr1 == NULL)
{
printf("空间申请失败\n");
return -1;
}
//程序执行至此,表示空间已经申请成功
printf("*ptr1 = %d, *ptr1 = %c\n", *ptr1, *ptr1); //没有初始化,默认是随机值
*ptr1 = 'H'; //给堆区空间进行赋值
printf("*ptr1 = %d, *ptr1 = %c\n", *ptr1, *ptr1); //没有初始化,默认是随机值
//单个申请4字节
int *ptr2 = (int *)malloc(sizeof(int)); //malloc(4)
if(NULL == ptr2)
{
printf("空间申请失败\n");
return -1;
}
printf("*ptr2 = %d\n", *ptr2); //随机值
*ptr2 = 520; //使用堆区空间
printf("*ptr2 = %d\n", *ptr2); //520
//手动将其释放
free(ptr1);
free(ptr2);
ptr1 = NULL;
ptr2 = NULL;
return 0;
}
#include<stdio.h>
#include<stdlib.h>
int main(int argc, const char *argv[])
{
//连续申请5个字节的空间
char *ptr1 = (char *)malloc(5); //malloc(sizeof(char)*5)
if(NULL == ptr1)
{
printf("空间申请失败\n");
return -1;
}
for(int i=0; i<5; i++)
{
printf("%c\t", ptr1[i]);
}
printf("\n");
//对堆区空间的使用
ptr1[0] = 'A';
ptr1[1] = 'B';
ptr1[2] = 'C';
ptr1[3] = '\0';
printf("ptr1 = %s\n", ptr1);
//申请连续的整形空间
int *ptr2 = (int *)malloc(sizeof(int)*5);
if(NULL==ptr2)
{
printf("空间申请失败\n");
return -1;
}
for(int i=0; i<5; i++)
{
printf("请输入第%d个元素:", i+1);
scanf("%d", ptr2+i); //&ptr2[i]
}
printf("您输入的元素分别是:");
for(int i=0; i<5; i++)
{
printf("%d\t", ptr2[i]);
}
return 0;
}
练习:在堆区申请8个int类型的空间,存储8名学生的成绩,并完成相关操作
1> 申请空间
2> 释放空间
3> 录入学生成绩
4> 输出学生成绩
5> 进行从大到小排序
每个功能要求使用函数实现
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/*定义申请空间函数
void apply_space(int **ptr, int n)
{
//需要对*ptr进行赋值
*ptr = (int *)malloc(sizeof(int)*n);
}
*/
//定义申请空间函数
int * apply_space(int n)
{
//开始申请空间
int *ptr = (int *)malloc(sizeof(int)*n);
if(NULL==ptr)
{
printf("空间申请失败\n");
return NULL;
}
//申请下来的空间中的值都是随机值
memset(ptr, 0, sizeof(int)*n); //给内存中进行设置初始值
//bzero(ptr, sizeof(int)*n);
//将地址返回
return ptr;
}
//定义输入分数函数
void input_score(int *ptr, int n)
{
//判断指针是否为空
if(NULL==ptr)
{
printf("录入失败\n");
return ;
}
//录入成绩
for(int i=0; i<n; i++)
{
printf("请输入第%d个学生的成绩:", i+1);
scanf("%d", &ptr[i]);
}
printf("录入成功\n");
}
//定义输出函数
void output_score(int *ptr, int n)
{
//判断指针是否为空
if(NULL==ptr)
{
printf("输出失败\n");
return ;
}
printf("当前学生成绩分别是:");
for(int i=0; i<n; i++)
{
printf("%d\t", ptr[i]);
}
printf("\n");
}
//对成绩进行降序排序
void sort_score(int *ptr, int n)
{
//判断指针是否为空
if(NULL==ptr)
{
printf("排序失败\n");
return ;
}
//排序
for(int i=1; i<n; i++)
{
for(int j=0; j<n-i; j++)
{
if(ptr[j] < ptr[j+1])
{
//交换
int temp = ptr[j];
ptr[j] = ptr[j+1];
ptr[j+1] = temp;
}
}
}
printf("排序成功\n");
}
//定义释放空间函数
/*
void free_space(int *ptr)
{
if(NULL != ptr)
{
free(ptr);
ptr = NULL; //防止野指针
}
}
*/
void free_space(int **ptr)
{
if(NULL != *ptr)
{
free(*ptr);
*ptr = NULL;
}
}
/******************8主程序*******************/
int main(int argc, const char *argv[])
{
//主程序中只需要获取堆区空间的内容即可
int *stu_ptr = NULL; //防止野指针
//让指针指向堆区空间
//1、以函数的参数进行传递
//apply_space(&stu_ptr, 8);
//2、以函数返回值将地址进行返回
stu_ptr = apply_space(8);
if(NULL == stu_ptr) //没有申请成功
{
return -1;
}
//向内存空间中输入数据
input_score(stu_ptr, 8);
//调用输出函数
output_score(stu_ptr, 8);
//调用排序函数
sort_score(stu_ptr, 8);
//调用输出函数
output_score(stu_ptr, 8);
//释放内存空间
/*free_space(stu_ptr);
stu_ptr = NULL;
*/
free_space(&stu_ptr);
//调用输出函数
output_score(stu_ptr, 8);
return 0;
}
野指针
1> 所谓野指针,就是指向非法内存地址的指针
2> 种类:
1、定义指针变量时,没有初始化,该指针变量存储的就是野指针
2、当指针指向数组时,数组下标越界后的指针也是野指针
3、指针原本有指向,但是指向的内存过期了(生命周期结束、手动释放) --> 悬空指针
4、指针函数返回的局部变量的地址,也是野指针
1、 int *ptr; //没有初始化的指针是野指针
2、 int arr[5] = {3,1,2,4,6};
int *qtr = arr;
qtr += 5; //此时的指针也是野指针
3、int *ptr = NULL; //非野指针
if(1)
{
int num = 520;
ptr = # //给指针变量赋值
}
ptr 指向了释放了的内存
//此处的ptr就是一个野指针
4、int *ptr = (int *)malloc(4);
free(ptr); //释放了内存
//此时的ptr也是野指针
5、int *fun()
{
int num = 520;
return #
}
int *ptr = fun();
//此时的ptr是野指针
杂项
预处理指令
1.作用:就是在程序执行之气那做一些简单的前置工作,例如条件编译、宏定义、文件包含等
2.分类:
1.文件包含:#include
2.宏定义:有参宏和无参宏,使用一个名字代替字符串的
3.条件编译:根据给定条件,判断某些程序是否被编译
3.文件包含指令
1.使用格式:#include<文件名.h>或者#include“文件名.h”
2.区别:使用尖括号包裹的文件,直接到库文件夹中寻找该文件 /usr/include/
使用双引号包裹的文件,会从可执行文件所在位置处(当前项目中)找该文件,如果没有,再去库中找
3.作用:就是将包含的文件在指令中展开
4.使用文件包含分文件编译
1.头文件(.h的文件):主要用于函数的声明,结构体的声明,宏定义、全局变量的定义
2.源文件(.c文件):实现函数的定义
3.主程序文件(包含main函数的.c文件):用于执行程序
4.一般而言,同一个文件的头文件和源文件的名称是一致的
头文件
int * apply_space(int n);
void input_score(int *ptr, int n);
void output_score(int *ptr, int n);
void output_score(int *ptr, int n);
void sort_score(int *ptr, int n);
void free_space(int **ptr);
源文件
#include<myhead.h>
/*定义申请空间函数
void apply_space(int **ptr, int n)
{
//需要对*ptr进行赋值
*ptr = (int *)malloc(sizeof(int)*n);
}
*/
//定义申请空间函数
int * apply_space(int n)
{
//开始申请空间
int *ptr = (int *)malloc(sizeof(int)*n);
if(NULL==ptr)
{
printf("空间申请失败\n");
return NULL;
}
//申请下来的空间中的值都是随机值
memset(ptr, 0, sizeof(int)*n); //给内存中进行设置初始值
//bzero(ptr, sizeof(int)*n);
//将地址返回
return ptr;
}
//定义输入分数函数
void input_score(int *ptr, int n)
{
//判断指针是否为空
if(NULL==ptr)
{
printf("录入失败\n");
return ;
}
//录入成绩
for(int i=0; i<n; i++)
{
printf("请输入第%d个学生的成绩:", i+1);
scanf("%d", &ptr[i]);
}
printf("录入成功\n");
}
//定义输出函数
void output_score(int *ptr, int n)
{
//判断指针是否为空
if(NULL==ptr)
{
printf("输出失败\n");
return ;
}
printf("当前学生成绩分别是:");
for(int i=0; i<n; i++)
{
printf("%d\t", ptr[i]);
}
printf("\n");
}
//对成绩进行降序排序
void sort_score(int *ptr, int n)
{
//判断指针是否为空
if(NULL==ptr)
{
printf("排序失败\n");
return ;
}
//排序
for(int i=1; i<n; i++)
{
for(int j=0; j<n-i; j++)
{
if(ptr[j] < ptr[j+1])
{
//交换
int temp = ptr[j];
ptr[j] = ptr[j+1];
ptr[j+1] = temp;
}
}
}
printf("排序成功\n");
}
//定义释放空间函数
/*
void free_space(int *ptr)
{
if(NULL != ptr)
{
free(ptr);
ptr = NULL; //防止野指针
}
}
*/
void free_space(int **ptr)
{
if(NULL != *ptr)
{
free(*ptr);
*ptr = NULL;
}
}
主程序
#include<myhead.h>
#include"03head.h" //相当于该文件中的代码写在此处
#include"03head.h" //相当于该文件中的代码写在此处
/******************8主程序*******************/
int main(int argc, const char *argv[])
{
//主程序中只需要获取堆区空间的内容即可
int *stu_ptr = NULL; //防止野指针
//让指针指向堆区空间
//1、以函数的参数进行传递
//apply_space(&stu_ptr, 8);
//2、以函数返回值将地址进行返回
stu_ptr = apply_space(8);
if(NULL == stu_ptr) //没有申请成功
{
return -1;
}
//向内存空间中输入数据
input_score(stu_ptr, 8);
//调用输出函数
output_score(stu_ptr, 8);
//调用排序函数
sort_score(stu_ptr, 8);
//调用输出函数
output_score(stu_ptr, 8);
//释放内存空间
/*free_space(stu_ptr);
stu_ptr = NULL;
*/
free_space(&stu_ptr);
//调用输出函数
output_score(stu_ptr, 8);
return 0;
}
宏定义
1.在C语言中,可以使用一个名字表示一个字符串或一类字符串,该名字是一个常量
例如:生活中的圆周率
2.宏仅仅是代指作用,在预处理阶段,仅仅将宏值取代宏名,不计算不做任何正确性检查
3.使用格式:
无参宏:#define 宏名 字符串
有参宏:#define 宏名(形参列表)包含形参列表的字符串
注意:有参宏定义中,形参没有数据类型,直接给定形参名即可
4.取消宏定义:#undef 宏名
#include<myhead.h>
#define PI 3.1415926 //无参宏
#define (MAX(x,y) x>y?x:y) //有参宏
int main(int argc, const char *argv[])
{
double num = PI+1;
printf("num = %lf\n", num); //4.141593
#undef PI //该指令过后,就没有PI这个宏了
//printf("num = %lf\n", PI); //? 取消了宏定义后,PI就不能用了
int key = 520;
int value = 1314;
int temp = MAX(key, value)+100; // (key>value?key:value)+100;
printf("temp = %d\n", temp); // ?
return 0;
}
条件编译
1.根据给定的条件,对某些程序代码进行编译,没有编译的程序肯定不会执行
2.判断宏是否存在
#ifdef 宏名
语句块1;
#else
语句块2;
#endif
判断宏值是否被定义了,如果定义了,则执行编译语句块1,否则编译语句块2
#ifdef/ifndef 宏名
语句块
#endif
通过宏值判断语句是否被编译
#if 表达式1
语句块1
#elif 表达式2
语句块2
#else
语句块3
#endif

1263

被折叠的 条评论
为什么被折叠?



