C语言指针用法总结

1、先谈谈内存与地址

引例:

计算机的内存看成大街上的一排房屋,每个房屋都要有门牌号,这个就相当于计算机的内存地址,而房屋里面住的人、家具等等就相当于需要存放的各种各样的数据,所以要想访问这些数据就得知道它的内存地址。

**bit:计算机的内存便是由数以亿万计的位(bit)**组成,每个位的容纳值为0或1。

  • byte:字节,一个字节包含8个位(bit),可以储存无符号unsigned类型的值为0-255(28-1),储存有符号signed类型的值为-128到127。无符号类型就是非负数,而有符号类型就是负数,0,正数。它也是可寻址的最小内存块。
  • word:字,是储存的基本单位,在计算机内存中基本是以一个word来储存数据的。

在16位的系统中(比如8086微机) 1字 (word)= 2字节(byte)= 16(bit)

在32位的系统中(比如win32) 1字(word)= 4字节(byte)=32(bit)

在64位的系统中(比如win64)1字(word)= 8字节(byte)=64(bit)

地址与字节的关系:

拿我本人的机器来举例吧,我的操作系统是64位的,1word=8byte=64bit,int类型在内存中占4个字节(64位+VS),

所以地址是4个连在一起的数字,用一般取地址符&输出的是变量的首地址。

地址就是以字节做单位的。指针类型占4个字节。

C类型所占字节数:

补充:数据类型所占的字节数或者位数实际上与操作系统的位数和编译器(不同的编译器支持的位数可能有所不同),反正具体某种数据类型所占的字节数是编译器根据操作系统的位数决定的,用例如==sizeof()==测一下就好。

C类型 32位(所占字节数) 64位(所占字节数)
char 1个字节 1
short int 2 2
int 4 4
wchar_t 2(宽字符) 2
char16_t 2(unicode字符) 2
char32_t 4(unicode字符) 4
float 4(6位有效数字) 4
double 8(10位有效数字) 8
int * 4 4

int i;//int类型占两个字节,16位(64位操作系统占4个字节),i在内存起始地址为6申请了2个字节的内存空间,并命名为i

char a;//char类型占一个字节,8位,a在地址为8上申请了1字节的内存空间,并命名为a

//将30存入变量i的内存空间
i=30;

//将字符't'存入变量a的内存空间
a='t';

//通过取地址符&,输出变量的首地址6
cout<<"i的地址为:"<<&i<<endl;

//输出变量i所储存的值
cout<<"i的值为:"<<i<<endl;

//通过取地址符&,输出变量的首地址8
cout<<"a的地址为:"<<&a<<endl;

//输出变量i所储存的值
cout<<"a的值为:"<<a<<endl;

2、再谈指针

//假设pi占2个字节宽度,实际上32位系统中,指针占4个字节
//指针变量pi在起始地址为8上申请了2个字节的内存空间
int *pi;

//将变量i的起始地址赋值给pi,所以pi的值为i的起始地址
pi=&i;

//输出指针变量p的首地址11
cout<<"pi的地址为:"<<&pi<<endl;

//输出变量i的首地址,因为pi的值被赋予为i的首地址
cout<<"pi的值为:"<<pi<<endl;

//通过解引用符*访问到变量i所储存的值
cout<<"pi所指向的值:"<<*pi<<endl;

*pi=20;//将通过解引用运算符访问到变量i并赋值为20,pi的值和地址都没有变化
cout<<"i的值为:"<<i<<endl;

变量pi的值就是分配给变量pi的内存空间所储存的数据,在上面这个例子中就是被赋予i的首地址6!

3、区别指针的类型,指针所指的类型,指针的值

(1)、指针的类型:

从语法角度看,把指针声明语句里面的指针变量的名字去掉,剩下的就是指针的类型。

(2)、指针所指的类型:

从语法角度看,就是把指针声明语句中的指针变量的名字和名字左边的指针声明符*去掉,剩下的就是指针所指的类型了。

(3)、指针的值:

**指针的值本是指针变量自身所储存的数值,但是例如int p1=&i;p1的值为i的地址,可分解为两句int p1;p1=&i;这样就不难理解了,p1所储存的值就是i的首地址,因为&i表示变量i的首地址。

在32位程序中(4个字节的程序),所有类型的指针的值都是一个32位的整数。因为32位程序里的内存地址都是32位长(4个byte)。

简而言之,指针的值占4个字节,所以说指针指向了i的内存空间,输出的值为i这块内存区域的首地址。

4、指针的算术运算:

int i=0;
int *p=&i;
cout<<p<<endl;//输出的是变量p保留的i的首地址
++p;//p的值加了4(sizeof(int)=1)
cout<<p<<endl;//输出的值为i的首地址+4

一个指针 ptrold 加(减)一个整数 n 后,结果是一个新的指针 ptrnew,ptrnew 的类型和 ptrold 的类型相同,ptrnew 所指向的类型和 ptrold所指向的类型也相同。ptrnew 的值将比 ptrold 的值增加(减少)了 n 乘sizeof(ptrold 所指向的类型)个字节。就是说,ptrnew 所指向的内存区将比 ptrold 所指向的内存区向高(低)地址方向移动了 n 乘sizeof(ptrold 所指向的类型)个字节。

指针和指针进行加减:

两个指针不能进行加法运算,这是非法操作,因为进行加法后,得到的结果指向一个不知所向的地方,而且毫无意义。两个指针可以进行减法操作,但必须类型相同,一般用在数组方面,不多说了。

5、运算符&和*:

这里&是取地址运算符*是间接运算符,也叫解引用操作符。

重点理解(&a)=20:*

&a表示变量a的地址,(&a)表示通过a的地址找到a,然后通过解引用符给其赋值为20。(int *p=&a; *p=20;这里的p就相当于&a,这样就比较好理解了。)

p 的运算结果就五花八门了。总之p 的结果是 p 所指向的东西,这个东西有这些特点:它的类型是 p 指向的类型,它所占用的地址是 p所指向的地址。

6、指针与数组的关系:

int a[]={1,2,3,4,5};
int i;
i=a[0];//i=*a;
i=a[3];//i=*(a+3)

数组名a代表数组本身,类型为int [],但是如果把a看作指针的话,它指向数组的第0个单元,类型为int *,所指向的类型为int。

下面总结一下数组的数组名(数组中储存的也是数组)的问题:

声明了一个数组 TYPE array[n],则数组名称 array 就有了两重含义:

  • 第一,它代表整个数组,它的类型是 TYPE[n];
  • 第二 ,它是一个常量指针,该指针的类型是 TYPE*,该指针指向的类型是 TYPE,也就是数组单元的类型,该指针指向的内存区就是数组第 0 号单元,该指针自己占有单独的内存区,注意它和数组第 0 号单元占据的内存区是不同的。该指针的值是不能修改的,即类似 array++的表达式是错误的。

在不同的表达式中数组名 array 可以扮演不同的角色:

在表达式 sizeof(array)中,数组名 array 代表数组本身,故这时sizeof 函数测出的是整个数组的大小。

在表达式array 中,array 扮演的是指针,因此这个表达式的结果就是数组第 0 号单元的值。sizeof(*array)测出的是数组单元的大小。

表达式 array+n(其中 n=0,1,2,…)中,array 扮演的是指针,故 array+n 的结果是一个指针,它的类型是 TYPE *,它指向的类型是 TYPE,它指向数组第 n 号单元。故sizeof(array+n)测出的是指针类型的大小。在 32 位程序中结果是 4。

sizeof(int(*)[10])=4

sizeof(int[10])=40

sizeof(ptr)=4

实际上,sizeof(对象)测出的都是对象自身的类型的大小,而不是别的什么类型的大小。

7、const int *pi与int *const pi:

const int i与int const i没有区别,const int *pi也与int const *pi没有区别,int与const那个放前放后都是一样的。

重点是*在const的左边还是右边:

  • 1) 如果 const 修饰在* pi的左边,则不能改的是* pi(即不能类似这样:* pi=50;赋值)而不是指 pi。
    只有通过给指针所向的变量赋值,才能是*pi改变:
    pi=&i;i=20;cout<<*pi<<endl;
  • 2) 如果 const 是直接写在 pi 前,则 pi 不能改(即不能类似这样:pi=&i;赋值),pi的地址永远只能指向初始化时的内存地址了,可以直接修改i的值,也可以通过 * pi来修改i的值。

补充:

情况一:int *pi 指针指向 const int i 常量的情况

const int i1 = 40;

int * pi;

pi = &i1;

//const int 类型的 i1 的地址是不能赋值给指向 int 类型地址的指针 pi 的。否则 pi 岂不是能修改 i1 的值了吗!

pi = (int * ) &i1;//强制类型转换可是 C 所支持的。

*p1=80;//编译能过但是i1的值还是40

情况二:const int *pi 指针指向 const int i1 的情况

const int i1=40;

const int * pi;

pi=&i1;//两个类型相同,可以这样赋值。很显然,i1 的值无论是通过pi 还是 i1 都不能修改的。

情况三:用 const int *const pi 声明的指针

int i;

const int * const pi=&i; //你能想象 pi 能够作什么操作吗?

pi值不能改,也不能通过 pi 修改 i 的值。因为不管是*pi 还是 pi 都是 const的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C语言基础指针详解教程

    目录 1.1:概述 1.1.1:内存 1.1.2:内存 1.1.3:指针和指针变量 1.2:指针基础知识 1.2.1:指针变量的定义和使用 1.2.2:通过指针间接修改变量的值 1.2.3:指针的大小 1.2.4:空指针与野指针 1.2.4:万能指针 1.2.5:const修饰的指针变量 1.3:指针与数组 1.3.1:数组名 1.3.2:指针操作数组 1.3.3:指针的加减运算 1.3.4:指针数组 1.4:指针基础小结 1.5:结语 1.1:概述 1.1.1:内存 内存含义: 储存器:用来存

  • C语言之初识指针

    指针是什么? 那到底什么是指针呢,其实指针和之前学习的变量基本相似,不过变量里面放的是一些值,而指针里面放的是它所指的地方的地址.在声明一个变量是,计算机就会为该变量预留一个位置,而指针所指☞的就是那个位置. 举个例子: int a = 10;//设置一个变量a的值为10 int *p = &a;//p这个指针里面就放的是a的地址 而&这个符号,就是取地址符,就像我们在使用scanf函数时  scanf("%d",&a); 这个a前面的&是一个意思,就是

  • C语言指针基础详解

    目录 1.1:概述 1.1.1:内存 1.1.2:内存 1.1.3:指针和指针变量 1.2:指针基础知识 1.2.1:指针变量的定义和使用 1.2.2:通过指针间接修改变量的值 1.2.3:指针的大小 1.2.4:空指针与野指针 1.2.4:万能指针 1.3:指针与数组 1.3.1:数组名 1.3.2:指针操作数组 1.3.3:指针的加减运算 1.4:指针基础小结 1.5:总结 1.1:概述 1.1.1:内存 内存含义: 储存器:用来存储程序和数据,辅助CPU进行运算处理的重要组成部分. 内存:

  • C语言函数指针的老生常谈

    目录 函数指针 函数指针的应用 函数指针作为参数实例(qsort函数) 总结 函数指针 本质上是一个指针,只不过指向函数而已. 编译器在编译期间对函数开辟了一块空间,而这快空间的开始地址,就是它的函数指针 . 下面我们也直接用最直观的程序来了解函数指针: #if 1 void func() { printf("hello ptr!"); } int main() { void (*p)(); p = func; p(); } #endif 在这里我们给出了func()函数,并在其中打印

  • C语言结构体指针引用详解

    目录 指向结构体变量的指针 指向结构体数组的指针 结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针. 指向结构体变量的指针 前面我们通过"结构体变量名.成员名"的方式引用结构体变量中的成员,除了这种方法之外还可以使用指针. 前面讲过,&student1 表示结构体变量 student1 的首地址,即 student1 第一个项的地址.如果定义一个指针变量 p 指向这个地址的话,p 就可以指向结构体变量 student1 中的任意一个成员. 那么,这个指针变量定义成

  • Go语言指针用法详解

    结合这个例子分析一下 结果: 结合以往C语言的基础,画了一张图来解释为什么会有上面这些值的出现.先查看下Go中的这两个运算符是啥吧. ①对于所有带a的结果 var a int = 1 定义了一个变量a值为1,如下图所示: &a就是这个存放a变量值的地址 *&a 就是指向&a的一个指针,*&a = a = 1 ②所有带b结果 var b *int = &a 类似C语言的 int *b = &a 定一个指向整形变量的指针b,b指向了a的地址 所以: b = &a

  • C语言指针用法总结

    1.先谈谈内存与地址 引例: 计算机的内存看成大街上的一排房屋,每个房屋都要有门牌号,这个就相当于计算机的内存地址,而房屋里面住的人.家具等等就相当于需要存放的各种各样的数据,所以要想访问这些数据就得知道它的内存地址. **bit:计算机的内存便是由数以亿万计的位(bit)**组成,每个位的容纳值为0或1. byte:字节,一个字节包含8个位(bit),可以储存无符号unsigned类型的值为0-255(28-1),储存有符号signed类型的值为-128到127.无符号类型就是非负数,而有符号

  • C语言指针详解及用法示例

    新手在C语言的学习过程中遇到的最头疼的知识点应该就是指针了,指针在C语言中有非常大的用处.下面我就带着问题来写下我对于指针的一些理解. 指针是什么? 指针本身是一个变量,它存储的是数据在内存中的地址而不是数据本身的值.它的定义如下: int a=10,*p; p=&a int a=10; int *p=&a; 首先我们可以理解 int* 这个是要定义一个指针p,然后因为这个指针存储的是地址所以要对a取地址(&)将值赋给指针p,也就是说这个指针p指向a. 很多新手都会对这两种定义方法

  • C语言指针与引用的区别以及引用的三种用法案例详解

    1.指针与引用的区别: 指针是一块内存的地址值,而引用是一块内存的别名. 下面引自://www.jb51.net/article/221791.htm 从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量). 在C++中,指针和引用经

  • Swift与C语言指针结合使用实例

    Objective-C和C的API常常会需要用到指针.Swift中的数据类型都原生支持基于指针的Cocoa API,不仅如此,Swift会自动处理部分最常用的将指针作为参数传递的情况.这篇文章中,我们将着眼于在Swift中让C语言指针与变量.数组和字符串共同工作. ####用以输入/输出的参数指针 C和Objective-C并不支持多返回值,所以Cocoa API中常常将指针作为一种在方法间传递额外数据的方式.Swift允许指针被当作inout参数使用,所以你可以用符号&将对一个变量的引用作为指

  • Go语言Cookie用法分析

    本文实例讲述了Go语言Cookie用法.分享给大家供大家参考,具体如下: web 开发免不了要和 cookie 打交道.Go 的 http 库也提供了 cookie 的相关操作. 复制代码 代码如下: type Cookie struct {   Name       string   Value      string   Path       string   Domain     string   Expires    time.Time   RawExpires string   Max

  • C语言 socketpair用法案例讲解

    socketpair()函数的声明: #include <sys/types.h> #include <sys/socket.h> int socketpair(int d, int type, int protocol, int sv[2]): socketpair()函数用于创建一对无名的.相互连接的套接子.  如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1]:否则返回-1,错误码保存于errno中. 基本用法:  这对套接字可以用于全双工通信,每一个套接字既

  • 带你分分钟玩转C语言指针

    目录 何为指针 数组指针 指针数组 字符串数组 数组指针的sao气操作 二级指针 函数指针 指针函数 文件指针 总结 何为指针 指针这玩意说白了,就是用来存储一个变量地址的东东 如图: (编辑器为vc2010) #include<stdio.h> void main(){ int a,*p; a=5; p=&a; printf("a=%d,p=%p,*p=",a,p,*p); getchar(); } 所以通过刚刚的情况,我们发现通过指针我们不仅可以获取一个变量的值

  • 深入了解Golang的指针用法

    目录 1.指针类型的变量 2.Go只有值传递,没有引用传递 3.for range与指针 4.闭包与指针 5.指针与内存逃逸 与C语言一样,Go语言中同样有指针,通过指针,我们可以只传递变量的内存地址,而不是传递整个变量,这在一定程度上可以节省内存的占用,但凡事有利有弊,Go指针在使用也有一些注意点,稍不留神就会踩坑,下面就让我们一起来细嗦下. 1.指针类型的变量 在Golang中,我们可以通过**取地址符号&**得到变量的地址,而这个新的变量就是一个指针类型的变量,指针变量与普通变量的区别在于

  • Go语言正则表达式用法实例小结【查找、匹配、替换等】

    本文实例讲述了Go语言正则表达式用法.分享给大家供大家参考,具体如下: Go语言的正则表达式使用很简单,示例代码: 复制代码 代码如下: package test import (     "fmt"     "regexp" ) func RegixBase() {     //findTest()     //findIndexTest()     //findStringTest()     //findChinesString()     //findNum

随机推荐