c-指针的理解

最近在学习MFC,其中的代码有点看的不是很深刻,究其原因还是对c语言中的指针理解的不是很好,下面详细的给大家介绍一下指针,如有不当之处,欢迎各位读者指正。

一.指针的概念

C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址。CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。这里,数据对象是指存储在内存中的一个指定数据类型的数值或字符串,它们都有一个自己的地址,而指针便是保存这个地址的变量。也就是说:指针是一种保存变量地址的变量

前面已经提到内存其实就是一组有序字节组成的数组,数组中,每个字节大大小固定,都是 8bit。对这些连续的字节从 0 开始进行编号,每个字节都有唯一的一个编号,这个编号就是内存地址。示意如下图:

这是一个 4GB 的内存,可以存放 2^32 个字节的数据。左侧的连续的十六进制编号就是内存地址,每个内存地址对应一个字节的内存空间。而指针变量保存的就是这个编号,也即内存地址。

二.为什么使用指针

在C语言中,指针的使用非常广泛,因为使用指针往往可以生成更高效、更紧凑的代码。总的来说,使用指针有如下好处:

1)指针的使用使得不同区域的代码可以轻易的共享内存数据,这样可以使程序更为快速高效;

2)C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等;

3)C语言是传值调用,而有些操作传值调用是无法完成的,如通过被调函数修改调用函数的对象,但是这种操作可以由指针来完成,而且并不违背传值调用。

三.如何申明一个指针

1 .声明并初始化一个指针

指针其实就是一个变量,指针的声明方式与一般的变量声明方式没太大区别:

int *p;        // 声明一个 int 类型的指针 p
char *p // 声明一个 char 类型的指针 p
int *arr[] // 声明一个指针数组,该数组有10个元素,其中每个元素都是一个指向 int 类型对象的指针
int (*arr)[] // 声明一个数组指针,该指针指向一个 int 类型的一维数组
int **p; // 声明一个指针 p ,该指针指向一个 int 类型的指针

指针的声明比普通变量的声明多了一个一元运算符 “*”。运算符 “*” 是间接寻址或者间接引用运算符。当它作用于指针时,将访问指针所指向的对象。在上述的声明中: p 是一个指针,保存着一个地址,该地址指向内存中的一个变量; *p 则会访问这个地址所指向的变量。

声明一个指针变量并不会自动分配任何内存。在对指针进行间接访问之前,指针必须进行初始化:或是使他指向现有的内存,或者给他动态分配内存,否则我们并不知道指针指向哪儿,这将是一个很严重的问题,稍后会讨论这个问题。初始化操作如下:

/* 方法1:使指针指向现有的内存 */
int x = ;
int *p = &x;  // 指针 p 被初始化,指向变量 x ,其中取地址符 & 用于产生操作数内存地址 /* 方法2:动态分配内存给指针 */
int *p;
p = (int *)malloc(sizeof(int) * );    // malloc 函数用于动态分配内存
free(p);    // free 函数用于释放一块已经分配的内存,常与 malloc 函数一起使用,要使用这两个函数需要头文件 stdlib.h

指针的初始化实际上就是给指针一个合法的地址,让程序能够清楚地知道指针指向哪儿

2. NULL指针

NULL 指针是一个特殊的指针变量,表示不指向任何东西。可以通过给一个指针赋一个零值来生成一个 NULL 指针。

#include "stdio.h"

int main(){
int *p = NULL;
printf("p的地址为%d\n",p); return ;
} /***************
* 程序输出:
* p的地址为0
***************/

以看到指针指向内存地址0。在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是为操作系统保留的。但是,内存地址 0 有一个特别重要的意义,它表明改指针不指向一个可访问的内存位置。

3.未初始化和非法的指针

如果一个指针没有被初始化,那么程序就不知道它指向哪里。它可能指向一个非法地址,这时,程序会报错,在 Linux 上,错误类型是 Segmentation fault(core dumped),提醒我们段违例或内存错误。它也可能指向一个合法地址,实际上,这种情况更严重,你的程序或许能正常运行,但是这个没有被初始化的指针所指向的那个位置的值将会被修改,而你并无意去修改它。

四.指针的运算

C 指针的算术运算只限于两种形式:

1) 指针 +/- 整数 :

   可以对指针变量 p 进行 p++、p--、p + i 等操作,所得结果也是一个指针,只是指针所指向的内存地址相比于 p 所指的内存地址前进或者后退了 i 个操作数。用一张图来说明一下:

在上图中,10000000等是内存地址的十六进制表示(数值是假定的),p 是一个 int 类型的指针,指向内存地址 0x10000008 处。则 p++ 将指向与 p 相邻的下一个内存地址,由于 int 型数据占 4 个字节,因此 p++ 所指的内存地址为 1000000b。其余类推。不过要注意的是,这种运算并不会改变指针变量 p 自身的地址,只是改变了它所指向的地址。

2)指针 - 指针

  只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去另一个指针。两个指针相减的结果的类型是 ptrdiff_t,它是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。举个例子:

五.指针与数组

在C语言中,指针与数组之间的关系十分密切。实际上,许多可以用数组完成的工作都可以使用指针来完成。一般来说,用指针编写的程序比用数组编写的程序执行速度快,但另一方面,用指针实现的程序理解起来稍微困难一些。

#include "stdio.h"

 int main(){
int arr[][] = {,,,,,}; // 定义一个二维数组并初始化
int (*p)[]; // 定义一个数组指针,指针指向一个含有3个元素的一维数组 p = arr; // 将二维数组的首地址赋给 p,此时 p 指向 arr[0] 或 &arr[0][0]
printf("%d\n",(*p)[]);             // 输出结果为 1
p++;                         // 对 p 进行算术运算,此时 p 将指向二维数组的下一行的首地址,即 &arr[1][0]
printf("%d\n",(*p)[]); // 输出结果为5 return ;
}

参考链接:https://www.cnblogs.com/tongye/p/9650573.html

c-指针的理解的更多相关文章

  1. C语言教学--二维数组和指针的理解

    对于初学者对二维数组和指针的理解很模糊, 或者感觉很难理解, 其实我们和生活联系起来, 这一切都会变得清晰透彻. 我们用理解一维数组的思想来理解二维数组, 对于一维数组,每个箱子里存放的是具体的苹果, ...

  2. 【C++】类中this指针的理解

    转自 苦涩的茶https://www.cnblogs.com/liushui-sky/p/5802981.html C++类中this指针的理解 先要理解class的意思.class应该理解为一种类型 ...

  3. 函数指针的理解 from 数据结构

    今天在学习数据结构中遇到一些问题,函数的指针不知道怎么用,给自己科普一哈 1 int LocateElem_Sq(SqList L, LElemType_Sq e, Status(*Compare)( ...

  4. C++中this指针的理解

    C++中this指针的理解 先要理解class的意思.class应该理解为一种类型,象int,char一样,是用户自定义的类型.用这个类型可以来声明一个变量,比如int x, myclass my等等 ...

  5. c++形参改变实参(对指针的理解

    这几天搞逻辑比较晕,居然把指针的概念都混淆了. eg:int *p;//当然不对指针初始化在有些编译器是通不过编译的,比如VS(尤其是选中了SDL) 指针p是一个对象,定义开始没有分配了内存空间,只是 ...

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

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

  7. 对于C语言中数组名是指针的理解

    我们都知道,c语言中数组名是一个指针,比如下面这段代码 #include<iostream>using namespace std;int main(){ int a[4]={1,2,3, ...

  8. C 语言指针怎么理解?

    对于程序员来说内存可以简化成这样一种东西:&lt;img src="https://pic1.zhimg.com/4d060c3f67c22cd4b07273db00f64708_b ...

  9. c语言函数指针的理解与使用

    1.函数指针的定义 顾名思义,函数指针就是函数的指针.它是一个指针,指向一个函数.看例子: A) char * (*fun1)(char * p1,char * p2); B) char * *fun ...

  10. C语言数组和指针的理解_在取地址运算上的操作_指针加减操作_a 和&a 的区别

    1.一个实例+理论分析 在了解数组和指针的访问方式前提下,下面再看这个例子: main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); pr ...

随机推荐

  1. SharePoint 获取服务器场管理员密码

    前言 这还是很久以前发生的故事(你也可以说事故),公司新来的小朋友帮客户运维,然后,因为客户要改场管理员密码,这个很简单啊,我们有密码变更的文档.小朋友分分钟就帮客户把密码更新了,然后,就去干别的了. ...

  2. 计算机二级-C语言-对标志位的巧妙使用。对二维数组数据进行处理。对文件进行数据输入。

    //函数fun的功能是:计算形参x所指数组中平均值(规定所有数均为正数),将所指数组中大于平均值的数据移至数组的前部,小于等于的移至后部,平均值作为返回值,在主函数中输出平均值和后移的数据. //重难 ...

  3. map的使用-Hdu 2648

    Shopping Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  4. ASP.NET FileUpload 上传文件类型验证

    验证的核心方法: public static bool IsAllowedExtension(FileUpload hifile) { //原方法是这样的,会提示找不到文件 //System.IO.F ...

  5. 排序算法之冒泡排序的python实现

    冒泡排序算法的工作原理如下: 1.  比较相邻的元素.如果第一个比第二个大(升序),就交换他们两个. 2.  对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大 ...

  6. 转发-【分享】思科无线控制器HA模式升级

    思科无线控制器HA模式下升级文档   当前使用版本:8.0.120.0 计划升级版本:8.2.151.0   其他工具: TFTP Server: 3CDaemon 远程登录:SecureCRT   ...

  7. Nginx Rewrite域名及资源重定向!(重点)

    第一步:搭建Nginx服务 第二步:修改主配置文件 [root@ns2 ~]# vim /usr/local/nginx/conf/nginx.conf user  nginx nginx; work ...

  8. 区分移动端和pc端

    区分移动端和pc端: window.navigator.userAgent.toLowerCase().indexOf('mobile')== -1   判断  等于-1就是pc,false就是移动端 ...

  9. 「AHOI2014/JSOI2014」奇怪的计算器

    「AHOI2014/JSOI2014」奇怪的计算器 传送门 我拿到这题首先是懵b的,因为感觉没有任何性质... 后来经过同机房dalao的指导发现可以把所有的 \(X\) 放到一起排序,然后我们可以发 ...

  10. 解决:使用 swiper 自动轮播图片,当拖动过 swiper 内的内容时,导致不继续自动轮播

    版本为1.3 当使用了 swiper 后: var mySwiper = new Swiper('.banner .swiper-container', { autoplay: 3000, loop: ...