C语言-指针讲解

合集下载

《C语言程序设计教程(第二版)》 第09章-指针(1)

《C语言程序设计教程(第二版)》 第09章-指针(1)

访问p_int所 指向的变量
getch();
}
程序运行结果: num_int=12, *p_int=12 num_f=3.14, *p_f=3.14 num_ch=p, *p_ch=p
2019/2/22
11
1、指针变量的定义
指针变量的定义标识符
数据类型 *指针变量[,*指针变量2……];
例如, [案例9.1]中的语句:
int num_int=12, *p_int ;
特别说明:定义而未初始化的指针变量(例如 p_int)是悬空的。
使用悬空指针变量,很容易破坏系统,导致系统 瘫痪。
2019/2/22
12
2、取地址运算 : &变量名 例 如 , [ 案 例 9.1] 中 的 &num_int 、 &num_f 、 &num_ch 的结果,分别为对应变量的地址 (num_int 、 num_f、num_ch)。 注意:指针变量只能存放相同数据类型变量的 地址。 例如, [案例9.1]中的指针变量p_int、p_f、p_ch, 只能接收int型、float型、char型变量的地址,否则出 错。
使p_int指向变量num_int
2019/2/22
10
printf(“num_int=%d, *p_int=%d\n”, num_int, *p_int); printf(“num_f=%4.2f, *p_f=%4.2f\n”, num_f, *p_f); printf(“num_ch=%c, *p_ch=%c\n”, num_ch, *p_ch);
9.3* 1维数组的指针与列指针变量 9.4 字符串的指针和指向字符串的指针变量 9.5 指针数组与主函数main()的参数 9.6 返回指针值的函数

C语言指针的长度和类型详解

C语言指针的长度和类型详解

C语言指针的长度和类型详解C语言指针的长度和类型详解指针是C语言的精髓,以下是店铺搜索整理的关于C语言指针的长度和类型详解,对于初学者深入理解C语言程序设计有很好的参考价值,有需要的朋友可以参考一下!想了解更多相关信息请持续关注我们店铺!一般来说,如果考虑应用程序的兼容性和可移植性,指针的长度就是一个问题,在大部分现代平台上,数据指针的长度通常是一样的,与指针类型无关,尽管C标准没有规定所有类型指针的长度相同,但是通常实际情况就是这样。

但是函数指针长度可能与数据指针的长度不同。

指针的长度取决于使用的机器和编译器,例如:在现代windows 上,指针是32位或是64位长测试代码如下:#include<stdio.h>#include<math.h>#include<stdlib.h>#include<stddef.h>struct p{int n;float f;};int main(){struct p *sptr;printf("sizeof *char: %d ", sizeof(char*));printf("sizeof *int: %d ", sizeof(int*));printf("sizeof *float: %d ", sizeof(float*));printf("sizeof *double: %d ", sizeof(double*));printf("sizeof *struct: %d ", sizeof(sptr));return 0;}运行结果如下图所示:指针相关的预定义类型:① size_t:用于安全地表示长度② ptrdiff_t:用于处理指针算术运算③ intptr_t:用于存储指针地址④ uintptr_t:用于存储指针地址分述如下:一、size_t类型size_t 类型是标准C库中定义的,应为unsigned int,在64位系统中为long unsigned int。

c语言 ●第10章 指针-1

c语言 ●第10章 指针-1
a[1] a[2]

19
2.定义时同时赋值
int a[10];
int *p=a; c规定: /* 相当于int *p=&a[0] */
若有 int a[10];
int *p=a; 则 p+1:指向下一个数组元素。

p+i:其指向下移i个元素。
20
说明:若有 int a[10]; int *p=a; (1) p+i *(p+i) = &a[i] a[i]= a+i *(a+i) (2)数组的指针变量也可带下标 a[i] ,p[i], *(a+i),*(p+i) 是等价的。 (3)a与p的区别:a代表数组a的首地址,是常量。 p=a; p也代表数组a的首地址,是变量。 如:p++; 是正确的,而 a++; 是错误的。 (4)引用数组元素有三种方法: 下标法: a[i]或p[i] 地址法:*(a+i) 效率低 指针法:*(p+i) *p++ 效率高
13
讨论: 若将被调函数swap( )改为: swap(int *p1,int *p2) {int *p; *p=*p1; *p1=*p2; *p2=*p; /*中间变量是指针变量所指的对象*/ } p无确定的地址(地址是随机的),可能指向任何单 元,有可能破坏系统(乱放枪)。加上int c;p=&c;就没 有问题了。
3 6 9 …
i j k
2004
3010
2000
i_pointer
3
二.对内存单位的访问 存数—写 取数—读 对内存单位的访问,是通过地址进行的。 如: printf(“%d”,i); 读 再如:scanf(“%d”,&i); 写 直接访问:按变量的地址直接读写变量的值。 如:k=i+j; (1)从2000开始的内存单元中取出i的值3. (2)从2002开始的内存单元中取出j的值6. (3)相加后,送入2004开始的内存单元。 间接访问:将变量a的地址存入另一变量b中,访问a时,先 找b,取出a的地址,再按此地址访问a。

全的C语言指针详解PPT课件

全的C语言指针详解PPT课件

在函数中使用指针参数
03
使用指针参数来访问和修改指针所指向的内容,需要使用“-
>”或“*”运算符。
05
指针的高级应用
指向指针的指针(二级指针)
定义与声明
二级指针是用来存储另一个指 针的地址的指针。在声明时, 需要使用`*`操作符来声明二级
指针。
初始化与使用
通过使用`&`操作符获取一个指 针的地址,并将该地址存储在 二级指针中。然后,可以通过 二级指针来访问和操作原始指
当使用malloc或calloc等函 数动态分配内存后,如果 不再需要该内存,必须使 用free函数释放它。否则, 指针将指向一个无效的内 存地址。
当一个指针在函数中定义 ,但该函数返回后仍然存 在并继续指向无效的内存 地址时,就会产生野指针 。
避免指针越界访问
总结词:指针越界访问是指试图访问数 组之外的内存,这是不安全的,可能会 导致程序崩溃或产生不可预测的结果。
指针与内存分配
通过指针来访问和操作动态分配的内存空间。指针可以 存储动态分配的内存地址,并用于读取和写入该地址中 的数据。
指向结构体的指针
01
定义与声明
指向结构体的指针是指向结构体类型的指针。在声明时,需要使用结
构体类型的名称来声明指向结构体的指针。
02 03
初始化与使用
通过使用`&`操作符获取结构体的地址,并将该地址存储在指向结构 体的指针中。然后,可以通过该指针来访问和操作结构体中的成员变 量。
```
பைடு நூலகம்
指向数组元素的指针
• 指向数组元素的指针是指向数组中某个具体元素的指针。通过将指针指向数组中的某个元素,可以访问该 元素的值。
• 指向数组元素的指针可以通过定义一个指向具体元素的指针来实现。例如,定义一个指向数组中第三个元 素的指针,可以使用以下代码

C指针详解(经典,非常详细)

C指针详解(经典,非常详细)

总结课:让你不再害怕指针指针所具有的四个要素:指针的类型,指针所指向的类型,指针指向的内存区,指针自身占据的内存。

0前言:复杂类型说明要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析.下面让我们先从简单的类型开始慢慢分析吧:int p;//这是一个普通的整型变量int*p;//首先从P处开始,先与*结合,所以说明P是一//个指针,然后再与int结合,说明指针所指向//的内容的类型为int型.所以P是一个返回整//型数据的指针int p[3];//首先从P处开始,先与[]结合,说明P是一个数//组,然后与int结合,说明数组里的元素是整//型的,所以P是一个由整型数据组成的数组int*p[3];//首先从P处开始,先与[]结合,因为其优先级//比*高,所以P是一个数组,然后再与*结合,说明//数组里的元素是指针类型,然后再与int结合,//说明指针所指向的内容的类型是整型的,所以//P是一个由返回整型数据的指针所组成的数组int(*p)[3];//首先从P处开始,先与*结合,说明P是一个指针//然后再与[]结合(与"()"这步可以忽略,只是为//了改变优先级),说明指针所指向的内容是一个//数组,然后再与int 结合,说明数组里的元素是//整型的.所以P 是一个指向由整型数据组成的数//组的指针int**p;//首先从P开始,先与*结合,说是P是一个指针,然//后再与*结合,说明指针所指向的元素是指针,然//后再与int 结合,说明该指针所指向的元素是整//型数据.由于二级指针以及更高级的指针极少用//在复杂的类型中,所以后面更复杂的类型我们就//不考虑多级指针了,最多只考虑一级指针.int p(int);//从P处起,先与()结合,说明P是一个函数,然后进入//()里分析,说明该函数有一个整型变量的参数//然后再与外面的int结合,说明函数的返回值是//一个整型数据int(*p)(int);//从P处开始,先与指针结合,说明P是一个指针,然后与//()结合,说明指针指向的是一个函数,然后再与()里的//int结合,说明函数有一个int型的参数,再与最外层的//int结合,说明函数的返回类型是整型,所以P是一个指//向有一个整型参数且返回类型为整型的函数的指针int*(*p(int))[3];//可以先跳过,不看这个类型,过于复杂//从P开始,先与()结合,说明P是一个函数,然后进//入()里面,与int结合,说明函数有一个整型变量//参数,然后再与外面的*结合,说明函数返回的是//一个指针,,然后到最外面一层,先与[]结合,说明//返回的指针指向的是一个数组,然后再与*结合,说//明数组里的元素是指针,然后再与int结合,说明指//针指向的内容是整型数据.所以P是一个参数为一个//整数据且返回一个指向由整型指针变量组成的数组//的指针变量的函数.说到这里也就差不多了,我们的任务也就这么多,理解了这几个类型,其它的类型对我们来说也是小菜了,不过我们一般不会用太复杂的类型,那样会大大减小程序的可读性,请慎用,这上面的几种类型已经足够我们用了.1、细说指针指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。

C语言指针详解

C语言指针详解

C语言指针详解1 程序如何运行当我们打开电脑中的任何一个程序运行时,我们的操作系统会将该程序存在硬盘的所有数据装载到内存中,然后有CPU 进行读取内存中的数据并进行计算,并将计算的结果返回给我们的操作系统,然后操作系统将相应的动作交付给相应的硬件来完成。

如:将声音数据交给声卡,最后有音响输出来,将图像交给显卡最后有显示器输出……但是还会有一部分数据会返回给内存,以供程序下面的语句继续使用。

我们都知道内存的容量有很大,如:4G,8G, 16G,有时候我们会打开很多的程序,所有的程序的数据都存放到我们的内存中,那么CPU是如何正确的读取我们的不同程序的数据并加以计算的哪?2 内存的假设设计为了让我们的CPU 可以很好的读取内存中的数据,内存必须做优化设计,于是给内存设定了集合设计,将我们的内存分成很多大小相同的方格(盒子),所有的数据将放入这些小盒子中,将不同的程序的数据放入到不同的小盒子中,这样就出现的模块化的内存,当我执行程序的一个命令时,CPU就会从相应的盒子读数据然后计算,由于我们硬件所能访问或计算的最小单位是字节,所以内存中的这样的一个小盒子的大小就给他规定一个字节。

3 地址和指针一般我们声明一块内存空间的时候,会给他取一个名字,为的是我们在编写程序的时候方便使用空间中存放的值,但是CPU 读数据的时候会忽视这个名字,因为CPU无法理解这样的数据,CPU 只能执行0,1代码,那么CPU是如何知道从什么地方读取数据,又到什么地方地址数据的读取的那,所以必须对内存做2次设计,就是将内存中分成的很多小盒子下面标注一些顺序的序号,例如:从第一个盒子开始,标注1,2,3,4,5,6,7,……每一个数字对应一个盒子,但是真正的内存如中不是使用这些十进制数字的,而是使用16进制整数表示的,如0x16ffee。

这些我们标记的数字就叫做内存中的地址。

由于这些地址和盒子是对应的关系,所以只要知道了地址,就可以得到对应盒子中存放的数据了,形象的说,我们说这个地址指向对应的盒子,在C语言中可以通过地址得到对应盒子的数据是*地址。

C语言指针用法详解

C语言指针用法详解

C语言指针用法详解C语言指针用法详解指针可以说是集C语言精华之所在,一个C语言达人怎么可以不会指针呢。

下面店铺给大家介绍C语言指针用法,欢迎阅读!C语言指针用法详解(1)关于指针与数组的存储a、指针和数组在内存中的存储形式数组p[N]创建时,对应着内存中一个数组空间的分配,其地址和容量在数组生命周期内一般不可改变。

数组名p本身是一个常量,即分配数组空间的地址值,这个值在编译时会替换成一个常数,在运行时没有任何内存空间来存储这个值,它和数组长度一起存在于代码中(应该是符号表中),在链接时已经制定好了;而指针*p创建时,对应内存中这个指针变量的空间分配,至于这个空间内填什么值即这个指针变量的值是多少,要看它在程序中被如何初始化,这也决定了指针指向哪一块内存地址。

b、指针和数组的赋值与初始化根据上文,一般情况下,数组的地址不能修改,内容可以修改;而指针的内容可以修改,指针指向的内容也可以修改,但这之前要为指针初始化。

如:int p[5];p=p+1; 是不允许的而p[0]=1; 是可以的;//int *p;p=p+1; 是允许的p[0]=1; 是不允许的,因为指针没有初始化;//int i;int *p=&i;p[0]=1; 是允许的;对于字符指针还有比较特殊的情况。

如:char * p="abc";p[0]='d'; 是不允许的为什么初始化了的字符指针不能改变其指向的内容呢?这是因为p 指向的是“常量”字符串,字符串"abc"实际是存储在程序的静态存储区的,因此内容不能改变。

这里常量字符串的地址确定在先,将指针指向其在后。

而char p[]="abc";p[0]='d'; 是允许的这是因为,这个初始化实际上是把常量直接赋值给数组,即写到为数组分配的内存空间。

这里数组内存分配在先,赋值在后。

(2)关于一些表达式的含义char *p, **p, ***p;char p[],p[][],p[][][];char *p[],*p[][],**p[],**p[][],*(*p)[],(**p)[],(**p)[][];能清晰地知道以上表达式的含义吗?(知道的去死!)第一组:char *p, **p, ***p;分别为char指针;char*指针,即指向char*类型数据地址的指针;char**指针,即指向char**类型数据的指针;他们都是占4字节空间的指针。

c语言指针的用法

c语言指针的用法

c语言指针的用法c语言是一种高级编程语言,它可以直接操作内存中的数据。

指针是c语言中一种特殊的变量,它可以存储另一个变量的地址,也就是内存中的位置。

通过指针,我们可以间接地访问或修改内存中的数据,从而实现更高效和灵活的编程。

本文将介绍c语言指针的基本概念、定义和初始化、运算和应用,以及一些常见的错误和注意事项。

希望本文能够帮助你掌握c语言指针的用法,提高你的编程水平。

指针的基本概念指针是一种数据类型,它可以存储一个地址值,也就是内存中某个位置的编号。

每个变量在内存中都有一个唯一的地址,我们可以用指针来记录这个地址,然后通过这个地址来访问或修改变量的值。

例如,假设有一个整型变量a,它的值为10,它在内存中的地址为1000(为了简化,我们假设地址是十进制数)。

我们可以定义一个指向整型的指针p,并把a的地址赋给p,如下所示:int a =10; // 定义一个整型变量a,赋值为10int*p; // 定义一个指向整型的指针pp =&a; // 把a的地址赋给p这里,&a表示取a的地址,也就是1000。

p = &a表示把1000赋给p,也就是让p指向a。

从图中可以看出,p和a是两个不同的变量,它们占用不同的内存空间。

p存储了a的地址,也就是1000。

我们可以通过p 来间接地访问或修改a的值。

指针的定义和初始化指针是一种数据类型,它需要在使用前进行定义和初始化。

定义指针时,需要指定它所指向的变量的类型。

初始化指针时,需要给它赋一个有效的地址值。

定义指针的一般格式为:type *pointer_name;其中,type表示指针所指向的变量的类型,如int、char、float等;pointer_name表示指针的名称,如p、q、ptr等;*表示这是一个指针类型。

例如:int*p; // 定义一个指向整型的指针pchar*q; // 定义一个指向字符型的指针qfloat*ptr; // 定义一个指向浮点型的指针ptr注意,在定义多个指针时,每个指针前都要加*号,不能省略。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。


主要涉及两个函数,即malloc//表示内存分配和free。//表示内存释放

malloc:在堆(heap)中分配一块指定大小的内存 free:释放乊前由malloc分配的内存。

堆的大小只受到操作系统寻址能力的限制(32位指针最大只能表示 4G内存) 动态内存最常见的用途乊一是实现动态数组。
见10substring.c
4.3 指针地址运算


指针(数组)可以不整数做加减运算,得到的是一个新的地址
假设p指向一个数组,那么:

p+1指向数组中的下一个元素。 p-1指向数组中的上一个元素。 p+4指向数组中的后面第4个元素 p-4指向数组中的前面第4个元素 p++令p指向数组中的下一个元素 p—令p指向数组中的上一个元素
见09arraypoint.c
4.2数组元素访问不指针


如果希望指针p指向a的第4个元素的地址,怎么办?
方法1:使用&运算符
p=&a[3];

方法2:使用+运算符
p=a+3;

方法2写起来更简单,因此更常见。 思考:想得到字符串str从第3个字符开始的字串,怎么办?
假设str为”12345678”,想得到”45678”。
(1)p2-p1
(2)*(p1)
(4)*a
10 (7)*(p1+3)+*( a+5) 8 0 0 (8)p1[4]+a[6] 10
(3)p1[0] 0
五、指针不动态数组

除了用作函数参数外,指针的另一个重要作用是用来实现动态内存管 理。

所谓动态内存,就是指大小、生存期都由你的代码自己来控制一块内存。
int a,b,*p; a=10;
内存地址1008
?
a
内存地址1004
? b
内存地址1000
?
p
2.1 &不*运算
int a,b,*p; a=10;
内存地址1008
10
a
内存地址1004
? b
内存地址1000
?
p
2.1 &不*运算
int a,b,*p; a=10; p=&a;
内存地址1008
10


b=*p; //把p指向的内存中的整数值赋给整形变量b。
*p=30;//将30赋给p指向的内存中 对于指针p,*p相当于一个普通变量!

见01points.c(使用调试单步执行查看结果)
2.1 &不*运算
int a,b,*p;
内存地址1008
?
a
内存地址1004
? b
内存地址1000
?
p
2.1 &不*运算
例如: char str[]=“Hello world!”; char s*=“Hello world!”;


C会为str在栈上分配一块13字节大小的内存,并将“Hello world!”这13 个字符拷贝到这块内存中。 相当于:char str[13];strcpy(str,”Hello world!”); 而s只是在栈上分配了4字节大小的内存,然后把“Hello world!”在程序 的常量数据区中的地址保存在s中。

4.4 数组参数不指针

在函数定义中,将参数类型定义为指针戒者定义为数组, 效果都是一样的

实际都是定义了一个指针类型的参数。 这是C语言的一个语法糖 //syntax sugar

同样,也可以将数组作为实参传递给指针类型的形参

见例14arrayparam.c
4.5 字符串不指针

使用字符数组与字符指针,最大的区别在于C对它们的初始化的处理 上。
为什么? 在函数swap(int *p1,int *p2)中,p1和p2是两个指针类型的 形式参数。

注意,在函数中,p1和p2各自指向哪里有变化吗?

变化的是*p1和*p2,即p1和p2指向的内存地址中保存的数据!
3.1 指针类型参数


swap(&i,&t)就相当于:
{ int *p1;p1=&i; int *p2=&t; int temp=*p1; *p1=*p2;

见11pointmath.c
4.3 指针地址运算


C语言中经常利用地址运算来处理字符串
例:模拟实现strcpy函数


见例12strcpy.c
注意,该程序使用了多个技巧,请认真思考体会:

字符串以0结尾 C语言中将0作为逻辑假,非0作为逻辑真 指针算数++;

函数形参改变丌影响实参
4.3 指针地址运算
6.1 结构指针不参数

使用结构指针来作为函数的形参是一种常见的函数定义方 式。 好处:


利用结构的成员,一次可以传入多项数据,从而简化了函数的定 义和调用


使用结构指针做形参,可以在函数中修改结构的成员
使用结构指针做形参,可以减少函数调用时参数内容复制的开销。

后面我们会大量使用结构指针来做形参!


在C语言中,两个同类型的指针可以做减法。
要让两个指针的减法p2-p1产生有意义的结果,需要满足 下面两个条件:

p2和p1指向同一个数组的丌同元素 p2指向的元素不p1相同,戒者在p1指向的元素乊后

则p2-p1表示p2和p1乊间差多少个元素,即p2指向的元素 不p1指向的元素的下标乊差 见13strlen.c,计算字符串长度
2.3 指针占用空间


sizeof(p)可以得到指针变量p所占用的空间大小
思考:int *p1; double *p2;

sizeof(p1)和sizeof(p2)哪个大?为什么?

因为我们使用的是32位的gcc编译器(dev-cpp自 带),所以每个指针的大小都是32位,即4个字节。 见04size.c
C语言程序设计 ——指针
林大 经管学院 瞿华
指针
一.
二. 三. 四. 五. 六. 七. 八.
指针是啥?
指针基本运算 函数中的指针 指针不数组 指针不动态数组
指针不结构
函数指针 指针数组不多重指针
九.
实验
一、指针是啥


什么是指针?
假设Z同学是我们班作业做得最好的同学,大家都喜欢参考他的作业。

*p1=temp;
} 很显然,这样是能交换i和t的内容的。
3.1 指针类型参数


使用指针参数的另外一个好处是节约栈空间。
见06stacksize.c。程序为什么会异常关闭?

由于函数调用时会为struct参数分配很大一块内存(1M字节), 超过了栈的现有空间大小,导致堆栈溢出。
函数调用时只需要为指针参数分配一块内存(还记得一个指针占 用多大空间吗?),所以就丌存在堆栈溢出问题了!

三、函数中的指针


折腾指针有啥用呢?
回忆一下函数的知识:

在函数中改变形式参数的值,会影响实际参数吗?为什么? 见05swap_1.c 函数的形式参数实质上是一个局部变量 函数执行时先将实际参数的值赋给形式参数 所以在函数中改变形式参数,不会影响实际参数

由于:

三、函数中的指针
Z==作业的标准答案 可以把Z看作是一个作业类型的普通变量……

某天A同学找Z:“把作业借我参考一下?”周X回答:“标准答案在 Y同学那里,你找他吧”

Z==“标准答案在Y那里” 这时候Z相当于一个指向别人(Y)的链接, 他就变成了一个指针!
一、指针是啥

指针(Point)实际上就是一个链接!
内存地址1000
1000
p
2.1 &不*运算
int a,b,*p; a=10; p=&a; b=*p;
内存地址1008
10
a
内存地址1004
10 b
内存地址1000
1000
p
2.1 &不*运算
int a,b,*p; a=10; p=&a; b=*p; *p=20;
内存地址1008
10
a
内存地址1004
10 b
内存地址1000
1000
p
2.1 &不*运算
int a,b,*p; a=10; p=&a; b=*p; *p=20;
内存地址1008
20
a
内存地址1004
10 b
内存地址1000
1000
p
2.1 &不*运算
int a,b,*p; a=10; p=&a; b=*p; *p=20; (*p)++;

五、指针不动态数组

普通数组主要有两个缺陷:

数组的大小是程序编写时决定的。为了保证数组的大小够用,通常需要 将数组定得很大,导致内存的浪费。

数组的大小受到栈空间大小的限制。

使用动态数组就可以解决这些问题。 见17dynamicarray.c 注意:使用动态内存分配时,一定要注意及时free不需要的内存。否 则就会造成内存泄漏。

Never ever返回指向函数局部变量的指针!
四、指针不数组

指针变量中保存的是地址。

也可以理解为,指针就是地址类型的变量。
相关文档
最新文档