11节:动态分配内存,二级指针,sizeof教程
指针是用来存储地址数据的变量
NULL表示空地址
记录无效地址的指针变量叫做野指针
指针可以参与如下数学计算
指针 + 整数,指针 - 整数,指针 - 指针
以上计算中所有整数都是有单位的,单位由指针的类型决定
静态局部变量的地址可以作为函数的返回值来使用
数组做函数形参时计算机内部使用指针替代它
对数组使用sizeof关键字计算的结果是整个数组的大小
对指针使用sizeof关键字计算的结果是指针变量本身的大小
数组名称取地址后得到的结果地址不变,但是级别和二维数组名称一致
指针变量本身的地址和它内部记录的地址无关
const声明的指针可以避免修改对应的普通变量
const关键字不安全
void*类型指针没有指定地址数据的来源
指针类型的指针必须先进行类型转换然后才能使用
类型转换分成隐式类型转换和强制类型转换
隐式类型转换由计算机自动完成
转换过程中会生成新变量,其中的二进制内容是从原变量中的二进制内容变化得到的。
强制类型转换有可能造成数据丢失
malloc函数可以从堆中分配多个连续的字节并把第一个字节的地址当成返回值
需要包含stdlib.h头文件
malloc函数失败则返回NULL
堆中变量的首地址一旦丢失则变量无法使用也无法释放
/*
malloc练习
*/
#include <stdio.h>
#include <stdlib.h>
int main() {
int * p_value = (int *)malloc(3 * sizeof(int));
if (p_value) {
//...
int *p_temp = p_value;
int pos = 0;
for (pos = 0;pos <= 2;pos++) {
*p_temp = pos + 1;
p_temp++;
}
for (p_temp = p_value + 2;p_temp >= p_value;p_temp--) {
printf("%d ", *p_temp);
}
printf("\n");
free(p_value);
p_value = NULL;
}
return 0;
}
使用free函数释放堆中分配的变量。
调用时一定要把分配时得到的首地址做参数
一段空间只能释放一次
malloc函数返回的地址可以作为函数的返回值使用,但这时就不可以在函数内部释放这些变量了。
练习:
1.编写函数分配三种类型的变量(char,short和int),变量的个数通过参数决定。
2.编写函数读取人员信息并记录到结构体变量中。最后把结构体变量的地址作为返回值。
/*
malloc练习1
*/
#include <stdio.h>
#include <stdlib.h>
typedef enum {CHAR, SHORT, INT} type;
void *alloc(type t, int size) {
switch(t) {
case CHAR:
return malloc(size * sizeof(char));
break;
case SHORT:
return malloc(size * sizeof(short));
break;
case INT:
return malloc(size * sizeof(int));
break;
}
}
int main() {
int *p_value = (int*)alloc(INT, 4);
if (p_value) {
free(p_value);
p_value = NULL;
}
return 0;
}
/*
malloc练习2
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[20];
float salary;
} person_info;
person_info *read(void) {
person_info *p_person = (person_info*)malloc(sizeof(person_info));
if (p_person) {
printf("请输入id:");
scanf("%d", &(p_person->id));
printf("请输入姓名:");
scanf("%s", p_person->name);
printf("请输入工资:");
scanf("%g", &(p_person->salary));
return p_person;
}
else {
return NULL;
}
}
int main() {
person_info *p_person = read();
if (p_person) {
printf("id是%d\n", p_person->id);
printf("姓名是%s\n", p_person->name);
printf("工资是%g\n", p_person->salary);
free(p_person);
p_person = NULL;
}
return 0;
}
calloc也可以从堆中分配变量,分配完成后把每个变量赋值成0
calloc函数要求使用不同的参数指定变量的个数以及变量的大小
realloc函数可以调整堆中空间的大小
memset函数可以给一组变量设置数值
/*
memset练习
*/
#include <stdio.h>
#include <string.h>
int main() {
int num = 0, pos = 0;
printf("请输入变量个数:");
scanf("%d", &num);
int values[num];
memset(values, 0, num * sizeof(int));
for (pos = 0;pos <= num - 1;pos++) {
printf("%d ", values[pos]);
}
printf("\n");
return 0;
}
二级指针是用来记录一级指针变量的地址数据的
二级指针既可以用来表示自己,也可以用来表示一个一级指针或一个普通变量
不可以把二维数组名称赋值给二级指针
指针数组名称可以赋值给二级指针
二级指针通常作为函数的形参使用
/*
二级指针练习
*/
#include <stdio.h>
int main() {
int value = 7;
int *p_value = NULL;
p_value = &value;
*p_value = 3;
int **pp_value = &p_value;
**pp_value = 5;
*pp_value = NULL;
return 0;
}
练习:
1.把释放指针的两条语句转移到一个函数中
/*
二级指针做形参的练习
*/
#include <stdio.h>
#include <stdlib.h>
void destroy(int **pp_value) {
free(*pp_value);
*pp_value = NULL;
}
int main() {
int *p_value = (int*)malloc(3 * sizeof(int));
if (p_value) {
destroy(&p_value);
}
return 0;
}
二级指针做形参可以让函数修改外部指针变量的内容
2.编写函数交换指针数组中的两个指针
/*
二级指针练习
*/
#include <stdio.h>
void swap(int **pp_value, int **pp_value1) {
int *p_temp = *pp_value;
*pp_value = *pp_value1;
*pp_value1 = p_temp;
}
int main() {
int value[] = {9, 4, 6, 2, 7}, pos = 0;
int *p_value[] = {value, value + 1, value + 2, value + 3, value + 4};
swap(p_value, p_value + 3);
for (pos = 0;pos <= 4;pos++) {
printf("%d ", *(p_value[pos]));
}
printf("\n");
return 0;
}