c指针在C编程语言中,指针是一个强大的工具。如果您正确使用它们,它们可以提高软件的效率 - 减少使用的内存量,并增加程序运行的快速。但是,很容易用指针造成错误,因此它们是崩溃的最常见原因之一。通过学习如何正确使用它们,您可以在不造成问题的情况下利用它们的灵活性。

如果您是C的新编程,您将享受学习本课程的C编程

什么是指针?

指针是一种变量。但是,当大多数变量都包含一个简单的值时,指针却包含了可以找到值的位置。

具有较旧的系统 - 特别是20世纪80年代的流行的8位家庭计算机 - 您可以将内存视为字节的“表”。单个字节的位置或“地址”是其在此表中的位置。

记忆映射

例如,当声明具有值25的单个字节变量(例如“char”)时,编译器可能会选择在0003 0003 000 003上放置该号码。

指针还占据内存中的条目并包含一个数字。但是,此数字是所引用的值的地址。

这很有用,因为指针变量中的地址可以更改为指向不同的位置,而不需要复制或影响现有数据。

在现代计算机系统中,内存排列比这更复杂。但是,它仍然有助于想象一下内存块作为这些表。

创建和使用指针

下面的示例代码声明了名为“v1”的整数变量。下一行创建指向指针v1

Int v1 = 8;Int *v = &v1;

指针的声明由数据类型、星号和要使用的名称组成。当将地址值赋给指针时,在目标变量前使用&符号。这是“地址”操作符。上面的赋值语句读取“指针的地址值”v等于变量的地址v1。”

如果将值输出到控制台,例如:

printf(“v1:%u \ n”,v1);printf(“v:%u \ n”,v);

第一行按预期打印第8号,但第二行显示不同的数字,因为v包含地址,而不是数字8。你需要输出那个数字v指着。为此,请使用指针名称前面的“取消引用”星号:

printf(“v:%u \ n”,* v);

改变指针

声明后,您可以随时重新分配指向其他地址的指针:

Int v1 = 8;Int v2 = 23;Int *v = &v1;printf("V: %u \n", * V);v = v2;printf("V: %u \n", * V);

首先printf ()声明输出值8v1。第二个相同的语句输出值23,因为指针v现在引用变量使用的内存v2

当将指针重新赋值到变量的地址时,必须记住使用地址操作符。下面的语句实际上是说“指针的地址值”v等于存储在中的值v2。”

v = v2;

它改变了指针v引用地址23的内存。如果然后尝试解引用,那么您访问的内存并不是您想要的。在现代环境中,操作系统可能会拒绝这种尝试并意外终止程序。

变化的值

要更改存储在内存地址的值,请将指针引用,使用“取消注释号:

* v = 7;

下面的代码给指针赋值v到变量使用的内存v1。然后更改存储在该地址的值。的printf ()声明表明该价值v1这种情况也会发生变化。

Int v1 = 8;Int *v = &v1;* v = 7;printf(“v1:%u,v:%u \ n”,v1,* v);

有时你会被迫使用指针:用于动态内存分配,或者使用操作系统库中的函数。有时你也会选择使用它们。

指针作为函数参数

当将变量传递给函数时,通常会创建数据的副本。这可以保护原始变量不被修改,但也会浪费内存和CPU资源。有时,您将需要您的函数修改原始变量。

与其他类型的变量一样,您可以将指针传递给函数。这样做比使用“全局变量”有一个显著的优势:你的函数可以转移到另一个项目或库中,而不需要创建全局变量。

声明接受指针的函数与使用常规参数声明函数不是非常不同:

void TestFunction(int *vx) {*vx = 0;}

然后,您可以向该函数传递一个指针并修改值v1间接:

Int v1 = 8;Int *v = &v1;testfunction(v);printf(“v1:%u \ n”,v1);

函数指针

许多编程语言都有复杂的方法来完成C语言可以轻松完成的事情:函数指针。

指针并不局限于引用变量,它们也可以指向包含函数的内存区域。例如,使用TestFunction ()上面,您可以使用声明和分配语句创建指向此函数的指针:

void(* fp)(int *)= testfunction;

这句话分为四个步骤:

  1. 说明函数的返回类型。
  2. 使用星号启动指针的名称并将其括在括号中。
  3. 在另一组括号中,声明与函数定义中使用的相同的参数,但不包含参数名称。
  4. 使用等分标志填写分配语句,并陈述目标函数的名称。

TestFunction ()现在可以使用指针调用:

fp (v);

您可以在运行时将指针重新分配给不同的函数,前提是新目标具有相同的返回类型和参数。因此,调用fp (v)可以运行不同的代码,这取决于在程序执行之前发生了什么。

您可以在结构中存储函数指针,甚至将它们作为参数传递给其他函数。

指针和数组

理解指针如何与数组一起工作的关键是知道数组已经是一种指针。

下面的数组声明声明Udemy.作为指向字符串中第一个字符的指针。字符串中的每个后续字符都保存在内存中的连续位置。

char udemy[] = " udemy ";

如下面的示例所示,数组和指针之间通常没有实际区别。

char udemy[] = " udemy ";Char *upp = udemy;printf("数组:%s \n", udemy);printf("指针:%s \n", upp);

赋值时不使用地址操作符UPP.。这仍然将字符串的地址放入UPP.因为Udemy.是地址,不是字符或字符序列。

因为数组指针,您通常可以以与阵列相同的方式处理指针。以下语句完全有效:

printf("Character 1: %c \n", upp[0]);

这意味着,虽然看起来很奇怪,但下面的内容也是完全可以接受的:

短x = 32597;Char *p = (Char *)&x;printf("字节1:%u \n", *p);printf("Byte 2: %u \n", p[1]);

简短是一个16位数字,由两个字节组成,它填充了内存中的两个连续位置。创建一个char指针x,参考数字的第一个字节的地址。使用带括号的数组寻址语法是访问第二个字节的简单方法。

还有另一种方式做同样的事情。由于指针的地址值是数字,因此“指针算术”可以通过内存移动指针。

函数调用:

printf("Byte 2: %u \n", p[1]);

可以写:

printf("Byte 2: %u \n", *(p+1));

如果通过此更改所示,即可使用此更改为示例代码,也可用于移动指针:

短x = 32597;Char *p = (Char *)&x;printf("字节1:%u \n", *p);P ++;printf(“字节2:%u \ n”,* p);

如果您不小心,您可以移动指针,直到它引用您允许使用的空间之外的内存。您必须避免执行此操作或程序可能会崩溃。

面向对象编程的指针

c++和Objective-C语言是作为C语言的扩展而开发的。这些是使语言能够与面向对象编程的原则一起工作所需要的。

c++和Objective-C都使用指针来保存存储在内存中的对象的位置,并支持本文描述的指针的其他用法。如果你想通过像从初学者到专家的C ++面向初学者的Objective C,你会发现它们的工作方式和你已经看到的一样。

C#中的顶级课程

用于初学者的#.NET
里克菲利普斯
4.4 (1264)
如何在Unity中使用c#编程像Minecraft一样的体素世界
Penny de byl,Penny @ holistic3d.com
4.6 (1420)
介绍c#中的并发-异步和并行
FelipeGavilán.
4.6 (56)
完成c# Unity Game Developer 3D
Ben Tristem, Rick Davidson(游戏开发者)电视团队
4.7 (26,879)
畅销书
C#中间:类,接口和OOP
Mosh Hamedani.
4.5 (23168)
畅销书
RPG核心战斗创造者:学习中级Unity c#编码
Ben Tristem, Rick Davidson, Sam Pattuzzi(游戏开发)电视团队
4.7 (8,503)
C#高级主题:准备技术访谈
Mosh Hamedani.
4.5 (15,134)
完成C#MasterClass
丹尼斯•Panjuta教程。Denis Panjuta的eu
4.5 (12079)
c#和。net中的设计模式
Dmitri Nesteruk
4.4 (7,126)
畅销书
c#开发人员:使用Visual Studio使你的编码速度翻倍
Mosh Hamedani.
4.5 (2,650)
畅销书
学习使用c#和。net进行并行编程
Dmitri Nesteruk
4.5 (2039)
畅销书

更c#的课程

C#学生也会学习

让你的团队。领导行业。

通过Udemy为Business获取组织的在线课程和数字学习工具库的订阅。

请求一个演示