学习基础C语言之六

2018.5.27
一维数组的数组名代表的是数组首元素的地址;
对一维数组名取地址,代表的是数组的地址;

二维数组的数组名代表的是第一个一维数组的地址;
对二维数组名取地址,代表的是二维数组的地址!

int a[3][2];
a[0]:是二维数组中第一个一维数组的数组名;
a[1]:是二维数组中第二个一维数组的数组名;
a[2]:是二维数组中第三个一维数组的数组名;

a : 第一个一维数组的地址;
a + 1: 第二个一维数组的地址;
a + 2: 第三个一维数组的地址;

②指针数组:首先是个数组,每个数组元素都是指针,也就是地址!

char *str[] = {"hello","world","linux"};

指针和函数的联系:
①指针函数:是一个函数,返回值是一个指针变量! //在函数的返回值方面,指针和函数的联系;

int *fun()
{

}
②函数指针:是一个指针,这个指针指向一个函数; //在函数名方面,指针和函数的联系;
对于函数的第二种调用方法;
首先你要知道的是:函数的地址,就是函数名!

1、定义一个函数指针;
怎么定义:
直接把函数的声明赋值过来,然后将函数名换成(*p); 

2、让函数指针指向某个函数,也就是给函数指针绑定函数;
p = 函数名; //

3、通过函数指针来调用函数;
将通过函数名调用的方法中,用(*p)来代替函数名;





③指针作为函数的参数; //函数的参数方面,指针和函数的联系;
int swap(int a,int b);
{
printf("a = %d\tb = %d\n",a,b);
int temp = 0;

temp = a;
a = b;
b = temp;

printf("a = %d\tb = %d\n",a,b);
}

int main()
{
int x = 10;
int y = 20;

swap(x,y);

printf("x = %d\n",x);
printf("y = %d\n",y);

return 0;
}

//数组名作为函数的参数;
// void fun(char *p) //既然实参是地址,那么形参来接收的应该定义一个变量能够
//保存传过来的地址! ===》指针变量!
void fun(char a[]) //数组名作为函数的形参,退化为指针处理!
{ //为什么需要[],如果没有[],就变成了char a ==》就是一个字符
//所以这里的[]表明是一个数组;

}

int main()
{
char str[] = "hello";

fun(str); //将数组名作为函数的实参,传递给参数
//因为数组名是数组首元素的地址,所以就相当于传递了地址;

return 0;
}

指针和字符串的联系:
char str[] = "hello";//这里面的hello是字符数组里面的;
char *p = "hello"; //这里的"hello"是字符串常量;
//字符串常量保存在.text段;不能够改变;
//用p来保存字符串常量的首地址!
*(p + 2) = 'q'; //试图修改常量区的内容!会报错!

//小程序:
// strlen:计算字符串的长度;
//my_strlen:计算字符串的长度;


char str[] = "ncjdncjdcnd";
int len = my_strlen(str);
printf("len = %d\n",len);


野指针和段错误;
什么叫野指针:
p保存的是int a的地址,那么就说 p指向a;

1、当指针指向不明确的时候;
int *p; //此时不知道p保存的是什么地址!
*p = 10;
2、指针保存的地址不存在!
int *p = 0x12345678;

2、指针指向明确,地址也存在,但是我们指向的空间没有操作权限;
int *p = NULL; //指向了0地址;但是0地址受系统保护,没有操作权限!
int b;
p = &b;

*p = 10;

满足上面三个条件之一,我们就称这个指针为野指针!

野指针会带来什么危害:
1、段错误!
其实就是地址错误:要么是地址不存在,要么是地址存在,而我们没有操作权限!
2、暂时没有危害,程序正常运行!
但是会在程序里面隐藏bug,以后在某个时间点会爆发!
3、程序直接崩溃!

怎么避免野指针?
归根到底就是养成良好的编码习惯;
1、定义指针的时候,随后给指针初始化为NULL;
2、当你使用指针要判断一下指针是否为NULL;
3、使用完指针的时候,要随后把指针变量指向NULL;

接下来几个关键字:
1、static:静态变量;
作用:
1、修饰局部变量的时候,可以延长局部变量的生命周期!
2、修饰全局变量或者函数的时候,可以起到“隐藏”的功能,进而达到只能够在本文件
中使用的目的,不能在别的文件中使用;


当定义一个静态变量,而没有初始化,系统会自动初始化为0;
static int num;
printf("num = %d\n",num);


2、const:修饰变量称为“常变量”;
int sum = 10;
int len = 9;

int const *p  = ∑

sum  = 18;
p = len;


3、register: 寄存器变量

修饰局部变量,不能够修饰全局变量和函数;
register int num = 10;
请求编译器,将register修饰的变量保存到CPU内部寄存器上!而不是保存到内存中!
进而提高读取效率!
CPU:皇帝;
内存:大臣;
寄存器:小太监;
既然是请求,编译器可以拒绝!因为CPU内部的寄存器数量有限!
既然register修饰的变量保存到CPU内部寄存器上!【所以变量的类型
CPU要能够支持!】而不是保存到内存中!【所以不能够用取地址符(&)来变量的地址】


4、extern;
5、volatile:防止编译器优化处理!


内存管理:
1、栈空间(stack):保存的是函数的形参,局部变量和自动变量;
特点:
1、自动管理:有系统自动给函数形参,局部变量和自动变量分配空间;
执行结束之后,系统自动释放,不用程序员自己去管;
2、反复使用:栈空间比较小;
3、栈空间是脏的;int  num;printf("num");
4、临时性;

2、堆空间(heap):用malloc 、realloc、calloc来申请空间;
特点:
1、灵活;
2、内存空间比较大;
3、需要手动申请和释放;
4、堆空间是脏的;
5、临时性;

怎么用:
//第一步:申请;如果申请成功返回的是申请到的堆空间的首地址;
char *str = (char *)malloc(100);
//第二步:检查是否申请成功;
if( str == NULL )
{
失败;
return;
}
//第三步:使用;
*(str + 1) = 'h';
str++;
//第四步:使用完释放;
free(str); //里面的参数是申请到首地址;

如果不手动释放,在程序结束之前这块空间就【内存泄露】;
当程序结束之后,由系统回收!

3、数据段:保存的是全局变量和被初始化为非0的静态变量;
4、.bss段:保存的是初始化为0的静态变量或者没有初始化的静态变量;
5、代码段(.text):函数的指令,以及字符串常量!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值