`C语言之指针(上) -----Day14`
一.知识点整理
1.指针基础概念
1.1 什么是指针?
简单的来说,指针就是一个数据类型,用来表示内存地址
1.2 直接访问和间接访问
- 直接访问
直接用过变量访问里面的值
’
- 间接访问
将一个变量的地址存放在另一个变量中,通过变量b来访问a的值
1.3 定义指针变量
- 声明 数据类型 *指针变量名
int *p ; char *q
1.4 指针初始化
- 指针在使用时一定要初始化,有两种方法
//方法一
int *p, a;
p = &a;
//方法二
int a;
int *p = &a;
如果指针未初始化,我们叫做野指针或者悬挂指针
1.5 指针操作符*和&
- ‘*’ 表示解引用符
可以用过*来访问指针变量所指向地址的变量
- &表示取地址符
用来取变量的地址
例如:*(&a) : 表示先取a的地址在访问a,相当于直接反问变量a
1.6 指针变量的大小
- 32位操作系统下:为4个字节
- 64位操作系统下:为8个字节
2. 指针与数组
2.1 定义和关系
- 数组元素的指针就是数组元素的地址
- 定义方法
int a[10]; // 定义10个整型的数组
int *p; // 定义指向整型变量的指针
p = a; // 把数组a元素的首地址给指针变量p
2.2 引用数组元素
- 下标法
a[i];
- 指针法
*(a+i) 或 *(p+1) // a表示数组名
2.3 指针作为形参传入函数
int main()
{
int a[10];
fun(a,10);
}
fun(int *a, int n){}
2.4 二维数组与指针
2.4.1 行指针与列指针
//定义一个二维数组
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[5];//表示p指向整一行,也称行指针
p = a;
printf(" a :%p\n",a);
printf(" p :%p\n",p);
p++;
printf(" p++ :%p\n",p);//偏移整一行的地址
- 行指针
行指针是一个二级地址,其指向的是一个一级地址
- 列指针
列指针是一个一级地址,其只想的是数组元素的地址
- 例题:声明几个指针变量取遍历二维数组并打印
int main()
{
int a[3][5] = {0};
int *p;
for(p = a; p < a+3; p++)
{
int *q = *p;
for(q=*p; q < *p+5;q++)
{
printf("%d",*q);
}
printf("\n");
}
}
2.5 字符串与指针
- 字符串指针
"1234"//值是字符串第一个元素的地址,直到'\0'
char *p = "1234";
char buf;
buf[] = "1234";
buf = "5678";//错的
"1234"为字符串常量,常量是不能够用变量的方式来修改
- 字符串赋值方式
char str[20];
str = "hello world!"
二. 难点易错点整理
1.内存单元是什么?变量名是什么?地址是什么?值是什么?
内存单元就是根据你所定义的数据类型所分配的,比如你定义了int型变量,那么系统就会给你分配4个字节的地址;
变量名就是用户自定义的名称,系统会自动为它分配相应的地址;
地址就是内存的编号,相当于你家的门牌号一样
值就是一定具体的常量,通俗一点就是门里面的你;
2. 32位操作系统:每一个进程都有4个G的虚拟内存,内存是如何进行分布的?
- 代码段
存放的是代码的指令,由各个函数产生,函数的每一个语句将最终经过编绎和汇编生成二进制机器代码,只读而且不能修改
- 只读数据段
存放的是全局变量、静态变量、字符串常量。const修饰的全局变量在常量区;const修饰的局部变量只是为了防止修改,没有放入常量区。
- 读写数据段(data)
通常已初始化的全局变量和局部静态变量被放在了读写数据段。
- 堆(heap)
是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
- 栈
栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
3.区分指针和指针变量
指针就是变量的地址,而用来存放地址的变量称为指针变量:指针变量的值是指针
4. 函数参数的传入
- 设计一个数组长度为10的数组, 随机取值范围0-9,
要求返回奇数的和和偶数的和,并返回奇数的个数
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int get(int *a,int *ji,int *ou)
{
int count = 0;
*ji = 0; *ou = 0;
for(int i = 0; i < 10; i++)
{
if(a[i] % 2 == 0)
{
*ou += a[i];
}
else if(a[i] % 2 == 1)
{
*ji += a[i];
count++;
}
}
return count;
}
int main()
{
int n1=0,n2=0,n3=0;
srand(time(NULL));
int a[10] = {0};
for(int i = 0;i < 10; i++)
a[i] = rand()%10;
for(int j = 0; j < 10;j++)
printf("%d ",a[j]);
printf("\n");
n3 =get(a,&n1,&n2);
printf("%d %d %d\n ",n3,n1,n2);
}
这个代码中是通过函数将多个函数值返回出来,而一般的return只能返回一个值,具体操作为**int get(int *a,int *ji,int *ou)**在函数里面定义了指针变量,并在主函数里面通过取地址符将值传入和传出
5. 数组指针与指针数组
数组指针就是通过指针来表示数组和操作数组的元素,而指针数组表示的是数组里面保存的是指针变量;
6.哪些情况会让程序报段错误
1.访问非法内存
2.修改只读常量
3.数组越界过多
三.自我总结
通过了一天对指针的学习,我也算是面对了我在C语言里面的心魔,知识点相比之前的函数、数组等,难度也提高了很多,与此同时知识的复杂度也提高了很多,相当的绕脑袋,就像指针、指针变量、数组指针、指针数组、数组a在主函数里面是常量,但是在函数里面却变成了地址等等,但是在学习之后,我也对这些概念有了一定的把握。
最后,送上一句话:孤臣万里,挑灯看剑,我与指针相缠绵!