七、指针
1:指针的作用是:实现内存的动态分配
变量:内存的位置。(Redis)数据库,也是保存在内存里面。
指针:内存的地址。
比方说,有一栋房子,你住进去了,是不是说明你占用了这个房子的位置,你在你家的宅基地上,盖了一间房子。 ——变量(占用了内存的位置)
你房子盖好了,但是没有地址,所以我们要申请一个地址,然后,让你通过这个地址可以找到我盖的房子—— 指针
所以说,我们实际做的任何事都是在操作内存空间。
而内存里面包含的是很多的操作指令
每个变量都有一个内存的位置,而每个内存的位置都定义了可使用&(地址符)运算符来访问地址。
#include "stdio.h"
int main()
{
int num1 = 100; // 这是一个变量,占用内存位置
int address1; // 声明了指针变量,只能赋值地址
address1 = &num1; // 通过地址符把变量转换成了指针
//返回的是一个16进制的地址符
printf ("num1 当前地址为: % p \n",address1);
int num2 = 200;
int address2;
address2 = &num2;
printf ("num1 当前地址为: % p \n",address2);
// 注意,分别改变 num1 num2 的值地址不会变化,因为 num1 num2 的位置已经定好了,改变的不是数
// 还有 double float char 数据类型的指针
int *ip;//整形指针
double *dp;//double类型的指针
float *fp;//float类型的指针
char *ch;//char类型的指针
//不同数据类型的指针之间唯一不同的是:指针所指向的变量或常量的数据类型不同!!!
int var = 20;
int *ip;
ip = &var;//指针变量中存储了var的地址
//通过指针赋值的变量的方式,去寻找到变量的地址
printf("var打印出来的地址:%p \n",&var);
printf("ip变量存储的地址:%p \n",ip);
printf("ip变量的值:%d \n",*ip);
return 0;
}
2:空指针
#include "stdio.h"
int main()
{
//通过变成的习惯,或是说,没有变量给我赋值的时候
//最好也有一个指针。
//空指针!!!不是0
int *ip = NULL;
//空指针也是有地址的
printf("空指针的地址 %p \n",ip);//ip = 00000000
//大多数操作系统的程序是不允许访问地址为0的内存,因为该内存是操作系统保留的。
//内存地址为0有特别重要的意义:它表明该指针不指向可访问的内存位置。
//当我们运行程序的时候,初始化一下数据(内存),释放内存。
int *str;//声明
free(str);//释放这个内存
str = NULL;
//进行内存的分配
str = (int*)malloc(sizeof(int));//初始化一个内存
if(str != NULL){
*str = 100;
}else{
//str为NULL(空指针的情况)
}
return 0;
}
3:野指针:就是内存地址的错误信息
通俗理解:你拿到了门牌号,但是找不到房子
如果出现了野指针,就要进行内存释放
成因
1)未初始化:定义指针变量时未赋初值,其值随机,指向不确定内存地址,如int *ptr; ,ptr 未初始化,值不确定。
2)内存释放后未置空:用free或delete释放指针指向内存后,指针未设为NULL(C 语言)或nullptr(C++ 语言),仍指向已释放内存,像int *p = (int *)malloc(sizeof(int)); free(p); 执行后,p 成野指针。
3)返回局部变量指针:函数返回指向局部变量的指针,函数结束局部变量内存释放,指针指向无效地址,比如int* func() { int num = 0; return # } ,func 函数返回的指针指向已释放的局部变量num 的内存。
4)指针越界:指针操作超出所指向内存范围,指向不属于程序的内存区域。
#include "stdio.h"
int main()
{
char *str;
gets(str);//标准的键盘输入
puts(str);//输出一个字符串
return 0;
}
八、请求头
1:单独引用 使用extern
//写它的原因:
//类比汽车驾驶的时候:1、启动 2、挂档 3、行驶
//程序运行的过程:1、预处理 2、编译 3、运行
//#include的作用就是程序的预处理部分
#include "stdio.h" //studio.h是系统封装好的请求头,处理了系统相关的操作方法
#include <windows.h>//操作windows电脑相关的方法
int main()
{
printf("helloworld");
return 0;
}
C语言 ——高级的编程语言;面向过程的语言,不具备封装、继承、多态——面向对象的特点
//home.c
#include "stdio.h"
int father()
{
printf("我的爸爸叫张帅\n");
return 0;
}
int mother()
{
printf("我的妈妈叫李美\n");
return 0;
}
int me()
{
printf("我叫张小美\n");
return 0;
}
//header.c
#include "stdio.h"
extern int father();
extern int mother();
extern int me();
int main()
{
father();
mother();
me();
return 0;
}
启动命令:
gcc header.c home.c -o header
./header
输出:我的爸爸叫张帅
我的妈妈叫李美
我叫张小美
2:复杂引用
//header.c
#include "stdio.h"
#include "home.h"
// extern int father();
// extern int mother();
// extern int me();
int main()
{
father();
mother();
me();
yeye(80);
return 0;
}
//home.c
#include <stdio.h>
//通过哪一个头文件进行了归类
#include "home.h"
int father()
{
printf("我的爸爸叫张帅\n");
return 0;
}
int mother()
{
printf("我的妈妈叫李美\n");
return 0;
}
int me()
{
printf("我叫张小美\n");
return 0;
}
int yeye(int age)
{
printf("爷爷今年%d岁\n",age);
return 0;
}
//home.h
#ifndef HOME_H
#define HOME_H
//把归类的函数放到这里面
int father();
int mother();
int me();
int yeye(int age);
#endif
启动命令:gcc header.c home.c -o header
./header
而不是 gcc header.c -o header
原因如下:gcc header.c -o header 只能编译 header.c 这一个文件,但程序需要同时编译并链接 header.c 和 home.c 两个文件,因为它们分别包含了主函数和函数实现。
1)编译与链接的区别
gcc header.c -o header 命令会编译 header.c 文件,但不会自动编译 home.c
虽然 header.c 中包含了 home.h 头文件(声明了函数原型),但头文件里只有函数声明,没有具体实现
函数的实际代码(实现)在 home.c 文件中,链接器需要这个文件来生成完整的可执行程序
2)链接错误的本质
当你执行 gcc header.c -o header 时,编译器只处理了 header.c
链接器在生成可执行文件时发现 father()、mother()、me() 这三个函数只有声明(在 home.h 中),但没有找到对应的实现代码
链接器无法从 header.c 中找到这些函数的实现,因为它们实际上在 home.c 中,所以报错
可以理解为大鱼吃小鱼

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



