指针的概念

指针也是一个变量,指针变量的值是另一个变量的地址

换句话说就是,指针存放的是一个内存地址,该地址指向另一块内存空间

指针变量的定义

指向一个变量的变量

int *p = NULL;
p = &i;
int *p = &i;

int *p; //表示定义一个指针变量

p = &i; //表示指针变量p指向i的地址

*p; //代表指针所指内存的实际数据

指针赋值的时候,一定要类型兼容(sizeof获取到的大小相同)

32位系统下,指针变量占4个字节,64位系统下,指针变量占8个字节。

*代表取值,即为指针指向内存的值

指针变量只能存放地址!!!

NULL的含义

一个指向NULL的指针,称之为空指针

这个指针不指向任何一个变量

野指针:没有赋初始值的指针

无类型指针

定义一个指针变量,但不指定它指向具体哪种数据类型

可以通过强制转化将void *转化为其他类型指针

可以用(void *)将其他类型指针强制转化为void类型指针

int i = 10;
void *p;
p = &i;
printf("*p = %d\n", *(int *)p);

在C语言当中,可以将任何一种地址赋值给void *指针

无类型指针不能参与运算,原因是不知道其大小,无法知道偏移单位

指针与数组的关系

int arr[10];代表开辟了十个连续的int存储空间,arr代表了数组的首地址。其值和&arr[0]相同。

int *p = arr;代表指针指向数组的首地址

在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址

指针操作数组

指针的运算代表的是指针的移动

int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr;

若存在以上定义,那么p+1代表了&arr[1]

在C语言中,数组名是一个常量,不可以参与运算

为何不能出现arr++?a++的意思是指向下一个内存空间,一旦这样做以后,会造成栈内存的回收问题,故编译器做了处理

*[]的本质其实是一样的

arr[i] ==> arr[0+i] ==> *(arr+i)

此时有p[i]等同于*(p + i)

*p++ == *(p++)

如果存在以下表达式

printf("%d",*(char *)p);

那么此时输出结果是什么呢?

分析:此时指针为char *类型,移动3位,int为四个字节,即移动到int字节末尾,如果是小端对其,那么输出0,如果是大端对其,那么输出1。

指针数组

char *p[5];

其本质是数组,代表有5个指针类型的数组,每个元素都是指针。总共有5个int *

此时取sizeof§得到的是4 * 5 = 20

此时p相当于是一个数组名,不可使用指针运算

数组指针

char (*p)[5];

定义了一个指针,指向int[5]这种数据类型的指针

其实质是一个二级指针

其本质是一个指针,指向5个int元素的指针,一般常用在数组,此时指向的数组其数据类型必须是相同的,其大小也必须相同。

此时取sixeof§得到的是4

此时p++的话偏移位置是sizeof(char) * 5

e.g.

char buff[5];
char (*p)[5];
p = buff;

二级指针

也就是指针的指针

int i = 10;
int *p1 = &i;
int **p2 = &p1;
printf("%d\n", **p2);

以上为二级指针的定义,此时有*p2代表p1的地址,**p2等于*p1又等于i

由此推出多级指针的概念

指向常量的指针与指针常量

const关键字

保护数组内容

如果将一个数组做为函数的形参传递,那么数组内容可以在被调用函数内部修改,有时候不希望这样的事情发生,所以要对形参采用const参数

func(const int array[])

指向常量的指针

可以限制指针修改变量的值,即不可通过*p来修改地址所存储的值

但可以更改指向的位置

const char *p;

指针常量

一旦初始化之后其内容不可改

p只能指向某个地址,不可修改指向的地址

char *const p;

指针中的const

看const修饰的是指针变量,还是修饰所指向的内存空间变量

void main(void)
{
const int a;
int const b;
const char *c;
char *const d;
const char *const e;
return;
}
  1. 前两个意思相同,代表一个常整型数
  2. 第三个:c是一个指向常整型数的指针(所指向的内存空间数据不能修改,但本身可以修改)
  3. 第四个:d是常指针(指针常量不能被修改,但是它所指向的内存空间可以被修改)
  4. 第五个:e是一个指向常整型的常指针(指针和它指向的内存空间均不能被修改)

    合理的利用const,尤其是指针做函数参数的时候,可以提高代码的可读性

指针运算

赋值:int *p = &a;

求值:int I = *p;

取指针地址:int **pp = &p;

将一个整数加(减)给指针:p + 3; p – 3;

增加(减少)指针值: p++,p--

求差值:p1 – p2,通常用于同一个数组内求两个元素之间的距离

比较p1 == p2:通常用来比较两个指针是否指向同一个位置

指针变量做函数参数

C语言中,函数的参数都是值传递,只能把实参的值传递给形参,而不可以把形参的值传递给实参

函数的参数可以是指针类型,它的作用是将一个变量的地址传送给另一个函数

一维数组名作为函数参数

当函数名作为参数时,C语言将函数名解释为指针

当数组名作为函数参数传递给被调用函数时,被调用函数是不知道数组有多少元素

int func(int arr[10];
int func(int arr[]);
int func(int *p);

以上函数定义等价

此时等价于地址传递,可以通过其地址改变实参的值

二维数组名作为函数参数

二维数组的指针操作使用int (*p)[5] = arr,做出如上定义以后,可以使用*(*(p + n) + m)来操作数组,也可以直接简写为p[n][m]来操作数组。

arr 二维数组名称,数组首地址
arr[0], *(arr + 0), *arr 0行,0列元素地址
arr + 1 第1行首地址
arr[1], *(arr + 1) 第1行,0列元素地址
arr[1] + 2, *(arr + 1) + 2, &arr[1][2] 第1行,2列元素地址
*(arr[1] + 2), *(*(arr + 1) + 2), arr[1][2] 第1行,2列元素的值

二维数组和一维数组一样可以作为函数参数,在二维数组做函数参数时可以不指定第一个下标

int func(int arr[][5]);
int func(int (*p)[5]);

指针做为函数的返回值

char *func()//返回值为char *类型的函数
{
return "test";//实际上返回的是test字符串的首地址,但这句话存在问题
}

指向函数的指针

指针可以指向变量,数组,也可以指向一个函数。

一个函数在编译的时候会分配一个入口地址,这个入口地址就是函数的指针,函数名称就代表函数的入口地址。

函数指针的定义方式:

int (*p)(int);

定义了一个指向int func(int n)类型函数地址的指针。

  1. 定义函数指针变量的形式为:函数返回类型(*指针变量名称)(参数列表)
  2. 函数可以通过函数指针调用
  3. int( * P)()代表指向一个函数,但不是固定哪一个函数

    e.g.
void func(int n)
{
printf("n = %d", n);
} int main()
{
void(*p)(int);//定义了一个指针,指向一个有一个int参数,同时返回值为void的指向函数的指针
p = func;//让p指向func3函数的入口地址
p(5);
}

把指向函数的指针做为函数的参数

将函数指针做为另一个函数的参数称为回调函数

指针小结

定义 说明
int i 定义整形变量
int *p 定义一个指向int的指针变量
int a[10] 定义一个int数组
int *p[10] 定义一个指针数组,其中每个数组元素指向一个int型变量的地址
int func() 定义一个函数,返回值为int型
int *func() 定义一个函数,返回值为int *型
int (*p)() 定义一个指向函数的指针,函数的原型为无参数,返回值为int
int **p 定义一个指向int的指针的指针,二级指针

指针和字符串

在C语言中,字符串其实就是char数组,所以其操作一般就是数组的操作,也就是指针的操作

char s[] = "hello word";
char *p = s;
p[0] = 'a';

C学习笔记-指针的更多相关文章

  1. c语言学习笔记 - 指针和字符串

    前面学习了字符串是一种字符数组,又知道了指针变量和数组的关系,这里来看一下指针和字符串的关系. #include <stdio.h> int main(void){ char str = ...

  2. C++学习笔记 指针与引用

    指针与引用  1. 指针 (1) 指针是一个变量(实体),存储的是一个地址,指向内存的一个存储单元,指针可以为空 (2) 指针可以为空,在声明定义时可以不初始化 (3) 指针在初始化之后可以重新指向其 ...

  3. C/C++学习笔记----指针的理解

    指针是C/C++编程中的重要概念之一,也是最容易产生困惑并导致程序出错的问题之一.利用指针编程可以表示各种数据结构,通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯:指针能 ...

  4. c语言学习笔记.指针.

    指针: 一个变量,其值为另一个变量的地址,即,内存位置的直接地址. 声明: int *ptr; /* 一个整型的指针,指针指向的类型是整型 */ double *ptr; /* 一个 double 型 ...

  5. C语言学习笔记--指针阅读技巧

    1. 指针阅读技巧:右左法则 (1)从最里层的圆括号中未定义的标示符看起 (2)首先往右看,再往左看 (3)遇到圆括号或方括号时可以确定部分类型,并调转方向 (4)重复 2.3 步骤,直到阅读结束 注 ...

  6. C语言学习笔记--指针和数组的关系

    1.数组的本质 (1)数组是一段连续的内存空间 (2)数组的空间大小:sizeof(array_type)*array_size; (3)数组名可看做指向数组第一个元素的常量指针 (4)数组声明时编译 ...

  7. C语言学习笔记--指针概念

    指针也是一种变量,占有内存空间,用来保存内存地址,在32位系统中指针的占用的内存大小为4个字节 1.*号的意义 (1)在指针声明时,*号表示所声明的变量为指针 (2)在指针使用时,*号表示取指针所指向 ...

  8. C/C++学习笔记--指针(Pointer)

    定义指针 一般类型: type_name  *  var_name; 例如: int _var = 1555; int * _var_addr=&_var; 一般类型数组类:type_name ...

  9. c语言学习笔记 - 指针和数组

    结合内存存储数据的机制,c语言里指针的出现和使用也就不奇怪了,如果先学了内存的一些知识,以及程序运行机制,到了c指针这块就会清晰很多. #include <stdio.h> int mai ...

随机推荐

  1. 【Python之路】特别篇--Python文件操作

    文件操作 open函数,该函数用于文件处理 操作文件时,一般需要经历如下步骤: (1)打开文件 (2)操作文件 一.打开文件 文件句柄 = open('文件路径', '模式','编码') 打开文件时, ...

  2. wind本地MySQL数据到hive的指定路径,Could not create file

    一:使用:kettle:wind本地MySQL数据到hive的指定路径二:问题:没有root写权限网上说的什么少jar包,我这里不存在这种情况,因为我自己是导入jar包的:mysql-connecto ...

  3. java+文件批量下载

    这篇文章主要介绍了Java实现批量下载选中文件功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下 1.在action中定义变量 private List<String> downLoa ...

  4. scanf的格式化字符串的匹配规则

    1.对于空白字符:空格.tab.回车等,scanf将忽略输入字符串的空白字符,直到下一个非空白字符,(并回放该非空白字符), 若该非空白字符与格式化字符串匹配,则读入 若该非空白字符与格式化字符串不匹 ...

  5. 数据结构图之三(最短路径--迪杰斯特拉算法——转载自i=i++

    数据结构图之三(最短路径--迪杰斯特拉算法)   [1]最短路径 最短路径?别乱想哈,其实就是字面意思,一个带边值的图中从某一个顶点到另外一个顶点的最短路径. 官方定义:对于内网图而言,最短路径是指两 ...

  6. 【Amaple教程】3. 模板指令与状态数据(state)

    一个模块的template模板.JavaScript和css之间的关系其实可以如下图表示: 如果你了解Angular.Vue动态模板,那你将会对Amaple的模板感到很熟悉,在Amaple中,temp ...

  7. 【译】OkHttp3 拦截器(Interceptor)

    一,OkHttp 拦截器介绍(译自官方文档) 官方文档:https://github.com/square/okhttp/wiki/Interceptors 拦截器是 OkHttp 提供的对 Http ...

  8. Python tuple 元组

    Python 元组 Python的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 如下实例: tup1 ...

  9. layui中从内置的分页中获取总记录数(转)

    封装的工具类: https://blog.csdn.net/QYHuiiQ/article/details/82147537

  10. jxbrowser java代码直接调用js代码

    https://blog.csdn.net/shuaizai88/article/details/73743669 final Browser browser = new Browser(); Bro ...