一、指针
首先理解一下内存单元:
计算机中内存最小的存储单位——内存单元。大小一个字节。 每一个内存单元都有一个唯一的编号(数)。称这个内存单元的编号为 “地址”。
再来理解一下指针变量:
存放地址的变量。
指针的定义和使用:
int a = 10;
int *p = &a; int* p;--- windows; int *p ---Linux int * p ;
*p = 250; 指针的 解引用。 间接引用。
p :将p变量的内容取出,当成地址看待,找到该地址对应的内存空间。如果做左值: 存数据到空间中;如果做右值: 取出空间中的内容。
指针的大小:指针的大小与类型 无关。 只与当前使用的平台架构有关。 32位:4字节。 64位: 8字节。
三种指针:
1.野指针:1)没有一个有效的地址空间的指针。 2)p变量有一个值,但该值不是可访问的内存区域。
1)没有一个有效的地址空间的指针。
int *p;
*p = 1000;
由于一开始声明的指针P没有指向一个地址空间,因此无法对p进行解引用。
2)p变量有一个值,但该值不是可访问的内存区域。
int *p = 10; //0-255的地址留给操作系统
*p = 2000;
不知道是否正确让P指向了一块可用地址
【杜绝野指针】
2.空指针:
int *p = NULL;
*p 时 p所对应的存储空间一定是一个 无效的访问区域。
3.万能指针/泛型指针(void *):
可以接收任意一种变量地址。但是,在使用【必须】借助“强转”具体化数据类型。
char ch = 'R';
void *p; // 万能指针、泛型指针
p = &ch;
printf("%c\n", *(char *)p);
const关键字的使用:
修饰变量:
const int a = 20;
int *p = &a;
*p = 650;
printf("%d\n", a);
//输出
650
【注意】用const修饰来定义的变量可用通过非const指针修改。
修饰指针:
1)const int *p; 可以修改 p,不可以修改 *p。
2)int const *p; 同上。
3)int * const p; 可以修改 *p,不可以修改 p。
4)const int *const p; 不可以修改 p,不可以修改 *p。
数据类型对指针的作用:
1)间接引用:
决定了从指针存储的地址开始,向后读取的字节数。 (与指针本身存储空间无关。)
2)加减运算:
决定了指针进行 +1/-1 操作向后加过的 字节数。
指针加减运算:
指针 * / % : 错误!!!
指针 +- 整数:
1) 普通指针变量+-整数
char *p; 打印 p 、 p+1 偏过 1 字节。
short*p; 打印 p 、 p+1 偏过 2 字节。
int *p; 打印 p 、 p+1 偏过 4 字节。
2)在数组中+- 整数
short arr[] = {1, 3, 5, 8};
int *p = arr;
p+3; // 向右(后)偏过 3 个元素
p-2; // 向前(左)偏过 2 个元素
3)&数组名 + 1
加过一个 数组的大小(数组元素个数 x sizeof(数组元素类型))
指针 +- 指针:
指针 + 指针: 错误!!!
指针 - 指针:
1) 普通变量来说, 语法允许。无实际意义。
2) 数组来说:偏移过的元素个数。
多级指针:
int a = 0;
int *p = &a; 一级指针是 变量的地址。
int **pp = &p; 二级指针是 一级指针的地址。
int ***ppp = &pp; 三级指针是 二级指针的地址。
int ****pppp = &ppp; 四级指针是 三级指针的地址。
二、数组
【数组名是地址常量】 --- 不可以被赋值。
获取数组中元素的方式:
int arr[] = {1,3, 5, 7, 8};
int *p = arr;
1)arr[i]
2)*(arr+0)
3)p[0]
4)*(p+0)
指针和数组的区别:
1)指针是变量。数组名为常量。
2)sizeof(指针) ===》 4字节 / 8字节
sizeof(数组) ===》 数组的实际字节数。
三、main函数
无参main函数:
int main(void) == int main()
带参数的main函数:
int main(int argc, char *argv[]) == int main(int argc, char **argv)
1)参数1:表示给main函数传递的参数的总个数。
2)参数2:是一个数组!数组的每一个元素都是字符串 char *
#include <stdio.h>
int main(int argc, char *argv[])
{
for(int i=0;i<argc;i++)
printf("argv[%d]=%s\n",i,argv[i]);
}
测试方法1:使用gcc编译生成可执行文件后调用可执行文件,如 test.exe I am a gcc test !
结果如下:
argv[0]=test.exe
argv[1]=I
argv[2]=am
argv[3]=a
argv[4]=gcc
argv[5]=test
argv[6]=!
测试方法2:在VS中的项目名称上 --》右键--》属性--》调试--》命令行参数 --》将 I am a vss test ! 写入。
结果如下:
argv[0]=D:\学习资料\C++学习项目\01-C语言\Day01\Debug\Day01.exe //这里的输出与你项目文件位置和名称相关
argv[1]=I
argv[2]=am
argv[3]=a
argv[4]=vs
argv[5]=test
argv[6]=!
四、函数相关
1)数组做函数参数:
void BubbleSort(int arr[10]) == void BubbleSort(int arr[]) == void BubbleSort(int *arr)
传递不再是整个数组,而是数组的首地址(一个指针)。所以,当整型数组做函数参数时,我们通常在函数定义中,封装2个参数。一个表数组首地址,一个表元素个数。
2)指针做函数返回值:
int *test_func(int a, int b);
指针做函数返回值,不能返回局部变量的地址值。
3)数组做函数返回值:C语言,不允许!!!! 只能写成指针形式。