C语言简析指针用途

目录
  • 对象的访问方式
  • 什么是指针
  • 指针变量
  • 与指针相关的运算符
  • 指针变量作为函数参数
  • 数组与指针
  • 多维数组与指针
  • 指针常量 和 常量指针
  • 指针数组 与 数组指针
  • 字符串与指针
  • 函数指针
  • 二级指针 与 多级指针

在C语言中,任何一个变量,都有两层含义:

(1) 代表该变量的存储单元的地址;变量的地址 左值 lvalue

(2) 代表该变量的值;右值 rvalue

对于一个变量的访问,只有两种情况:

一是把一个值写到变量的地址中去 (lvalue)

二是从变量的地址中取变量的值 (rvalue)

对象的访问方式

直接访问 : 通过对象名去访问

如:

			int a;
			a = 1024;
			b = a;

注:直接访问 受到作用域的限制

间接访问 :

通过对象的地址去访问,指针访问。

只要你知道了对象的地址,就可以在任何地方去访问它。

不受作用域的限制。

什么是指针

存储单元(如: memory 内存)的地址:

分配给每个对象的内存单元都有一个编号,这个编号就是我们所说

存储单元的地址。并且存储单元按照字节来编号。

在C语言中,指针的概念与地址差不多的,你可以直接认为指针就是一个地址。

一个变量的地址,我们也称为变量的“指针”

& 取地执符

单目运算符, “取xxx对象的地址”

通过一个对象的指针去访问它,首先要解决对象的指针(地址) 的保存问题。

需要定义另外的一个变量去保存它的地址,这种变量我们称为指针变量。

指针变量

指针变量也是一个变量,也是用来保存数据,只不过指针变量保存的数据是其他对象的地址。

指针变量的定义:

指向的对象的类型 * 指针变量名;

“指向的对象的类型” :

指针变量指向的对象的类型,而不是指针的类型。

如:

int *p;
int a=10;
p=&a;//p保存了对象a的地址
	//  p 指向 a

与指针相关的运算符

& : 取地址符

int a;

&a : 表示取对象a的地址

对象a的地址,其实就是对象a的指针。

* : 指向运算符  ,单目运算符

*地址(*指针): 地址对应的那个变量(对象)。

int a=10;
int *p=&a;
int b=*&a;//b=10,int b=a

所以*(&a) <=> a

*& 可以直接约掉 (编译原理状态机的词法分析)

指针变量作为函数参数

传递的还是值!! 只不过这个“实参的值”可能是某个对象的地址!

C语言中,函数参数的传递只能是"值传递"

形参 = 实参的值

野指针:

void XXX2(int * m, int * n)
		{
			int * t;//定义了一个指针变量t, 但是t没有被赋值
					//t没有赋值,但是不代表它没有值,相反它会有一个相对应的
					//不知道这个值是多少 undefine
			*t = *m; //操作野指针,可能导致 段错误(对一个未知的空间进行写操作)
			*m = *n;
			*n = *t; //操作野指针,可能导致 段错误(对一个未知的空间进行读操作)		

*t 放置到 ‘=’ 符号的左边,代表t指向对象的左值

对t的指向的对象进行写的操作

*t 放置到 ‘=’ 符号的右边,代表t指向对象的右值

对t的指向的对象进行read的操作

所以t是一个“野指针”,我们也不知道 t指向的内存空间是否可读可写,

如果不可读或者不可写,那么后续对*t操作,就会导致内存的非法访问 => 段错误!!

空指针:

NULL 0

在计算机中地址为0的存储空间是不存在的

如果一个指针的值,指向空(NULL)的指针,称之为空指针。

int *p=NULL;
*p=1024;//操作空指针
int b=*p;//操作空指针

我们去使用空指针,一定会 造成内存的非法访问 => 段错误

数组与指针

数组元素与普通变量是一样的,数组元素也有自己的地址。

数组元素也有左值和右值,并且数组元素间的地址是相邻的。

数组名可以代表首元素的地址。

a => &a[0], 数组名a当做指针来看

int a[]={1,2,3};
int *p=a;//a是数组名当指针来看,==&a[0]

指针作加减的问题:

能不能通过指针p去访问a[1]?

p=p+1;//&a[0]+1==&a[1]

p + i (p是一个指针,i是一个整数值)

注:不是简单地加减数值,而是加减i个指针指向单元的长度。

p + 1 => 往后面挪了一个int单元的长度 ,&a[1]

			int a[10];
			int * p = a; // p = &a[0]
			a[1] <=> *&a[1] <=> *(&a[0] + 1) <=> *(a + 1) <=> a[1]
			a[1] <=> *&a[1] <=> *(&a[0] + 1) <=> *(p + 1) <=> p[1]

数组名a,在代码中有两层含义:

int a[10];

(1) 数组名代表整个数组

&a : 取整个数组a的地址。

&a + 1 : 往后面挪了1个(int[10])单元长度。

(2) 在合适情况下面,数组名可以当作指针来看

a <=> &a[0]

a + 1 : 当作指针来看

=> &a[0] + 1

=> &a[1]

多维数组与指针

在C语言中,所有的数组其实都是一维数组!

int a[3][4]; //int[4] a[3]; 

表达式         表达式的含义                              表达式的值 
          a             数组名: 
                          (1) 当作指针 &a[0]                     取整个一维数组a[0]的地址 
                          (2) 当作整个数组来看       
          a[0]             数组名: 
                           (1) 当作指针 &a[0][0]                  取数组元素a[0][0]的地址 
                           (2) 当作整个一维数组a[0]来看 
          a[0][0]       数组元素a[0][0]                           a[0][0] (左值/右值)

a + 1          a是数组名,在此处当作指针 ==&a[0]+1==&a[1]
 a[0] + 1       a[0] 是数组名,在此处当作指针 ==&a[0][0]+1==&a[0][1]
a[0][0] + 1       a[0][0]是二维数组a中的一个int类型的元素 ==a[0][0]+1
a[1] + 2         a[1]是数组名,此处当作指针 ==&a[1][0]+2==&a[1][2]
*(a + 1) + 2    a是数组名,在此处当作指针 ==*(&a[0]+1)+2==*(&a[1])+2==a[1]+2==&a[1][2]

指针常量 和 常量指针

他们都是指针,只不过他们之间的属性有一点区别。

指针常量:

指针本身不能改变(指针的指向不能变),但是

它所指向的内存空间里面的内容是可以改变的。

最具有代表性例子,数组名!

定义方式:

指向对象的类型 * const 指针变量名;

				int a , b;
				int * const p = &a;
				p = &b ; //error

常量指针:

是一个指向常量的地址。指针指向的对象是常量,

那么指针本身的指向是可以改变的,但是这个指针指向

内存空间中的内容是不能够改变。

最具有代表性例子,字符串

char * p = "abcde"; //"abcde" <=> &'a' 

定义方式:

const 类型 * 变量名;

or

类型 const * 变量名;

指针数组 与 数组指针

(1) 指针数组

指针数组是一个数组,只不过它里面的每一个元素都是指针罢了!

定义数组:

数组元素类型 数组名[元素个数];

“数组元素类型” : C语言中任意合法的类型都可以。

int * p[4]; //定义了一个指针数组,数组名为p,里面含有4个int*类型的指针。

(2) 数组指针

数组指针是一个指针,只不过这个指针是用来指向一个数组罢了!!

int (*p)[4] ; //定义了一个数组指针,指针变量名为p,用来指向一个含有4个int类型元素的数组的。 

int a[3][4];
int (*p)[4];
p = a; //&a[0]
*(*p + 1) // *(a[0]+1)==*(&a[0][1])==a[0][1]
*(*(p + 2)) // *(*(&a[2]))==*(&a[2][0])==a[2][0]
*(*(p+3) + 3)// *(*(&a[0]+3)+3)==*(*(&a[3])+3)==*(&a[3][0]+3)==a[3][3]

字符串与指针

字符串就是一串字符。在C语言中,没有字符串这个类型。

C语言字符串是通过 char *(字符指针)来实现。

C语言中的字符串,是用""引起来的一串字符来表示,并且字符串后面默认会加一个\0,\0(ASCII为0的那个字符)字符串结束的标志。

"abc"  //字符串 
            "\n"   //字符串 
            ""     //字符串 => 空串 
            '\123' //字符
            '\n'   //字符

注:

我们只需要保存字符串的首字符地址就可以了,从首字符地址开始找到第一个\0,前面的这些字符就是字符串里面的字符。

在C语言中的字符串(如: “ssssssabcd”)是保存在一个叫做 .rodata(只读数据)的内存区域,字符串代表是这个内存空间的首地址。

"ssssssabcd" => 表达式的值  => &'s'
			char *p="12345" ==&'1'
				int *p=&'1';
				p+1=&'2';

字符数组:

			char s[5] = {'a', 'b', 'c', 'd', 'e'};
			//字符数组,与普通数组是一样的,保存在一个.data/栈空间
			//数组区域是可读可写的
			sizeof(s) == 5
			strlen(s) >= 5 //没有'\0' 长度不确定
			char s[] = {"abcde"}; //自动生成'\0'
			<=> char s[] = {'a', 'b', 'c', 'd', 'e', '\0'};
			//s字符数组,与普通数组是一样的,保存在一个.data/栈空间
			//数组区域是可读可写的
			sizeof(s) == 6
			strlen(s) == 5
			char s[] = {"abcde"};
			s[1] = 'B'; //OK
			char ch = s[1]; //OK
			*(s + 1) = 'B'; //OK
			ch = *(s + 1); //OK
			s = s + 1; //ERROR
						//s是数组名,数组名当作指针,指针常量
						//s的指向 是不能够改变的,但是s指向的内存空间
						//里面的内容是可变的
			printf("%s\n", s); //abcde   %s : char* 地址
			//把后面的那个地址当作是一个字符串的首地址,一个一个字符进行输出,直到遇到\0才会结束!
					

函数指针

函数也有地址 ,那么咱们可以定义一个指针,去存放一个函数的地址,像这样的指针,称为函数指针。

函数指针如何定义

int *  abc(int a, float b)
			{
			}

描述函数abc的类型: int (int , float ) : 是一个返回值为int类型,带有一个Int类型和float类型的参数的函数类型

指向函数的返回值的类型 (*指针变量名) (指向函数的形参类型列表);

int (* p)(int, int) ;

定义了一个指针变量p,p是一个函数指针,是用来指向一个返回值为int类型,并且带有两个int类型参数的函数的。

函数指针如何赋值

&函数名

or

函数名 : 在C语言中,函数名本身就可以代表函数的地址

通过函数指针去调用指向的函数,有如下两种方案:

p为函数的指针。

(1) (*p)(实参列表)

(2) p(实参列表)

int *p=abc//函数名
p(a,b);//调用函数

二级指针 与 多级指针

int a,b;

可以定义一个指针变量p1,来保存变量a的地址:

int *p1=&a;
b=*p1=*&a=a;//通过指针p1访问a变量

可以定义一个指针变量p2,来保存变量p1的地址:

int *p2=&p1
int b=**p2=*p1=a//通过指针p2访问a变量

p2保存的是一个一级指针p1的地址,所以说,

p2指向一个一级指针,p2就是一个二级指针

可以定义一个指针变量p3,来保存变量p2的地址:

int *p3=&p2;
int b=***p3=**p2=*p1=a;

p3保存的是一个二级指针p2的地址,所以说,

p3指向一个二级指针,p3就是一个三级指针

到此这篇关于C语言简析指针用途的文章就介绍到这了,更多相关C语言指针内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言指针如何实现字符串逆序反转

    目录 指针实现字符串逆序反转 知识点 字符串逆序的几种写法 非递归写法 递归写法 指针实现字符串逆序反转 #include<stdio.h> #include<string.h> void rec(char* arr) { //int len = sizeof(arr); // 判断字符串长度需要用strlen. int len = strlen(arr); printf("字符串长度len = %d\n", len); char* p1 = arr; char

  • C语言深入浅出分析函数指针

    目录 我们先看一个代码: #include<stdio.h> void test() { printf("haha\n"); } int main() { printf("%p\n", test); printf("%p\n", &test); return 0; } 输出的是两个地址,函数名就是函数的地址 将函数的地址存起来: #include<stdio.h> void test() { printf(&quo

  • C语言八道笔试题精讲带你掌握指针

    目录 题目一 题目二 题目三 题目四 题目五 题目六 题目七 题目八 为了题目的准确性和我们一般学习过程中的习惯,这里所有的题目代码都是在 X86 环境(32 位平台)下运行的. 题目一 #include <stdio.h> int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); return 0; } /

  • C语言sizeof和strlen的指针和数组面试题详解

    目录 一.概念 sizeof: strlen: 二.例题及解析 2.1 一维数组 2.2 字符数组 2.3 二维数组 三.总结 一.概念 sizeof: sizeof操作符的结果类型为size_t,(它在头文件用typedfe定义为unsigned int类型),计算的是分配空间的实际字节数.sizeof是运算符,可以以类型.函数.做参数 . strlen: strlen结果类型也为size_t(size_t strlen( const char *string )),但strlen是计算的空间

  • C语言例题讲解指针与数组

    目录 1.概要复习 2.指针与数组笔试题 2.1一维数组 2.2字符数组 2.3字符串数组 2.4字符串指针 2.5二维数组 1.概要复习 本篇的内容主要围绕指针与数组.指针与字符串等之间的关系,以及进一步理解sizeof .strlen 的使用与意义. 数组是指具有相同类型元素的集合,字符串常量是一个指向在连续空间里存放的字符的首字符的地址的指针.我们会在下面理解数组与字符串数组的不同. sizeof 是一个操作符,是计算类型空间大小的.strlen 是针对字符串的库函数,用来求字符串的长度.

  • C语言利用面试真题理解指针的使用

    目录 前言 笔试题一 笔试题二 笔试题三 笔试题四 笔试题五 笔试题六 笔试题七 笔试题八 前言 大家好~我又来了,今天给大家带来的是指针的几道笔试题,希望能够加强大家对指针知识的把握,指针就应该这样学! 笔试题一 #include<stdio.h> int main() { int a[5] = { 1 , 2 , 3 , 4 , 5 }; int* ptr = (int*) (&a + 1); printf("%d, %d", *(a + 1), *(ptr -

  • C语言超详细讲解指向函数的指针

    目录 一.函数的指针 二.指向函数的指针变量 三.调用函数的两种方式 四.指向函数的指针的作用 五.用指向函数的指针作函数参数(重点) 六.为什么要将指向函数的指针变量作为函数的形参(重点) 一.函数的指针 首先,函数名代表函数的起始地址,调用函数时,程序会从函数名获取到函数起始地址,并从该地址起执行函数中的代码,函数名就是函数的指针,所以我们可以定义一个指向函数的指针变量,用来存放函数的起始地址,这样一来,就可以通过该变量来调用其所指向的函数. 二.指向函数的指针变量 定义指向函数的指针变量

  • C语言学习之指针知识总结

    目录 一.地址 二.指针与指针变量 三.指针的作用 四.初学指针时常见的错误 五.通过调用函数修改主调函数中的值 六.指针与一维数组 七.使用函数操作一维数组 八.指针变量所占字节数 九.静态数组的缺陷 十.malloc函数 十一.动态数组的构造 十二.静态内存与动态内存的对比 十三.多级指针 十四.跨函数使用内存 一.地址 内存中的最小单元是字节,一个字节对应一个编号,这里的编号就是对应字节的地址.换句话说,地址就是内存单元的编号. 二.指针与指针变量 指针与指针变量是两个不同的概念,指针是某

  • C语言简析指针用途

    目录 对象的访问方式 什么是指针 指针变量 与指针相关的运算符 指针变量作为函数参数 数组与指针 多维数组与指针 指针常量 和 常量指针 指针数组 与 数组指针 字符串与指针 函数指针 二级指针 与 多级指针 在C语言中,任何一个变量,都有两层含义: (1) 代表该变量的存储单元的地址:变量的地址 左值 lvalue (2) 代表该变量的值:右值 rvalue 对于一个变量的访问,只有两种情况: 一是把一个值写到变量的地址中去 (lvalue) 二是从变量的地址中取变量的值 (rvalue) 对

  • 简析Python函数式编程字符串和元组及函数分类与高阶函数

    目录 函数式编程中的字符串 不变类型元组 普通元组的声明与访问 函数式的分类 any() .all() .len().sum() 对比学习 zip().reversed().enumerate() 高阶函数 函数 max 和 min() map 函数 filter 函数 sorted 函数 同一需求的不同效率问题 函数式编程中的字符串 在函数式编程中,经常用到 Python 字符串,因其是不可变数据结构. 字符串本身是一个对象,具备很多对象方法,与常识中函数的使用不太相同,例如下述代码 my_s

  • Oracle的数据字典技术简析

    正在看的ORACLE教程是:Oracle的数据字典技术简析.数据字典是Oracle存放有关数据库信息的地方,其用途是用来描述数据的.比如一个表的创建者信息,创建时间信息,所属表空间信息,用户访问权限信息等.当用户在对数据库中的数据进行操作时遇到困难就可以访问数据字典来查看详细的信息. Oracle中的数据字典有静态和动态之分.静态数据字典主要是在用户访问数据字典时不会发生改变的,但动态数据字典是依赖数据库运行的性能的,反映数据库运行的一些内在信息,所以在访问这类数据字典时往往不是一成不变的.以下

  • ASP的Error对象知识简析

    在VBScript中,有一个On Error Resume Next语句,它使脚本解释器忽略运行期错误并继续脚本代码的执行.接着该脚本可以检查Err.Number属性的值,判别是否出现了错误.如果出现错误,返回一个非零值.在ASP3.0中,也可以使用OnErrorGoto0"转回到"缺省的错误处理.在ASP2.0中实际也进行这种处理,但是没有相应文档说明,这在很多asp数据相关处理文件中司空见惯,加上On Error Resume Next,关闭缺省的错误处理,然后用err抓住, If

  • 基于Oracle的面向对象技术入门基础简析开发者网络Oracle

    正在看的ORACLE教程是:基于Oracle的面向对象技术入门基础简析开发者网络Oracle.一.概述 对象是Oracle8i以上版本中的一个新的特性,对象实际是对一组数据和操作的封装,对象的抽象就是类.在面向对象技术中,对象涉及到以下几个重要的特性:  封装性 通过对数据和操作的封装,将用户关心的数据和操作暴露出来作为接口,其他数据和操作则隐藏到对象内部,这样便于用户使用和维护.  继承性 对象具有继承性,通过这一特性可以增强程序的可扩展性,适合大型项目的开发.  多态性 同一操作在运行时刻有

  • java JDBC系列教程之JDBC类的简析与JDBC的基础操作

    什么是JDBC? 概念:JAVA Database Connectivity Javas数据库连接,Java语言操作数据库接口,然后由各个数据库厂商去实现这个接口,提供数据库驱动java包,我们可以使用这套接口,真正执行的是jar驱动包中的实习类 使用一张图让大家更为直观的理解: coder就是写这套接口的程序员 JDBC的使用步骤 1.导入驱动jar包 2.注册驱动 3.获取数据库连接对象 4.定义sql执行语句 5.获取sql语句执行对象 6.执行sql语句返回结果 7.处理结果 8.释放结

  • 简析Linux网络编程函数

    目录 1,创建套接字socket 2,绑定套接字bind 3,创建监听:listen 4,等待连接accept 5, 收发消息send和recv 6,关闭套接字描述符close 7,基于tcp协议的C/S服务器模型 8,实现代码 网络编程的一些基本函数:也是实现tcp协议通讯的基本步骤,实现代码在最后,IP需要修改为自己的IP,即可通信: 1,创建套接字socket 函数原型: #include<sys/types.h> #include<sys/socket.h> int soc

  • Python函数式编程之面向过程面向对象及函数式简析

    目录 Python 函数式编程 同一案例的不同写法,展示函数式编程 面向过程的写法 面向对象的写法 接下来进入正题,函数式编程的落地实现 Python 函数式编程的特点 纯函数 Python 函数式编程 Python 不是纯粹的函数式语言,但你可以使用 Python 进行函数式编程 典型的听君一席话,如听一席话,说白了就是 Python 具备函数式编程的特性, so,可以借用函数式语言的设计模式和编程技术,把代码写成函数式编程的样子 一般此时我会吹嘘一下,函数式代码比较简洁和优雅~ 好了,已经吹

  • C++中关键字 override 的简析

    目录 在C++中,虚函数是最常见的实现多态的机制之一,来个最简单的例子温习一下: class Base // 基类 { public: virtual void f(){cout << "Base::f()" << endl;} }; ​ class Derived1 : public Base // 派生类1 { virtual void f(){cout << "Derived1::f()" << endl;} }

  • C语言全方位讲解指针与地址和数组函数堆空间的关系

    目录 一.一种特殊的变量-指针 二.深入理解指针与地址 三.指针与数组(上) 四.指针与数组(下) 五.指针与函数 六.指针与堆空间 七.指针专题经典问题剖析 一.一种特殊的变量-指针 指针是C语言中的变量 因为是变量,所以用于保存具体值 特殊之处,指针保存的值是内存中的地址 内存地址是什么? 内存是计算机中的存储部件,每个存储单元有固定唯一的编号 内存中存储单元的编号即内存地址 需要弄清楚的事实 程序中的一切元素都存在于内存中,因此,可通过内存地址访问程序元素. 内存示例 获取地址 C语言中通

随机推荐