好吧,我基本上理解了如何使用指针,但是不了解如何最好地使用它们以进行更好的编程。
有什么好的项目或要解决的问题,包括使用指针,以便我可以更好地理解它们?
好吧,我基本上理解了如何使用指针,但是不了解如何最好地使用它们以进行更好的编程。
有什么好的项目或要解决的问题,包括使用指针,以便我可以更好地理解它们?
Answers:
指针概念使您可以按地址引用数据,而不必重复存储数据。这种方法允许编写高效的算法,例如:
排序
在排序算法中移动数据时,您可以移动指针而不是数据本身。您可以节省很多不必要的数据移动。
链接列表
您可以存储下一个和/或上一个项目位置,而不是与记录关联的整个数据。
传递参数
在这种情况下,您传递数据的地址而不是数据本身。再次考虑运行在数百万行上的名称压缩算法。
的概念可以扩展到数据结构,例如关系数据库,其中一个指针是类似于一个外键。某些语言不鼓励使用诸如C#和COBOL之类的指针。
可以在许多地方找到示例,例如:
以下帖子可能在某种程度上相关:
令我惊讶的是,没有其他答案提到过:指针允许您创建非连续和非线性的数据结构,其中一个元素可能以复杂的方式与多个其他元素相关联。
链表(单链,双链和循环链),树(红黑,AVL,特里,二进制,空间分区……)和图都是可以最自然地根据引用而非值构造的结构示例。
一种简单的方法是多态。多态仅适用于指针。
另外,在需要动态内存分配时,可以随时使用指针。在C语言中,这通常发生在需要将数据存储到数组但不知道编译时大小的情况下。然后,您将调用malloc分配内存和访问它的指针。同样,无论您是否知道,使用数组时都在使用指针。
for(int i = 0; i < size; i++)
std::cout << array[i];
等于
for(int i = 0; i < size; i++)
std::cout << *(array + i);
这些知识使您可以做一些很酷的事情,例如在一行中复制整个数组:
while( (*array1++ = *array2++) != '\0')
在c ++中,可以使用new为对象分配内存并将其存储到指针中。您可以在需要在运行时而不是在编译时创建对象的任何时候执行此操作(即,方法将创建一个新对象并将其存储到列表中)。
为了更好地理解指针:
查找一些使用继承的项目。
这是我不遗余力的项目:
从文件中读取两个nxn矩阵,并对它们执行基本的向量空间运算,并将其结果打印到屏幕上。
为此,您将必须使用动态数组并通过指针引用您的数组,因为您将拥有两个数组数组(多维动态数组)。完成该项目之后,您将对如何使用指针有一个很好的了解。
要真正理解指针为什么如此重要,您需要了解堆分配和堆栈分配之间的区别。
以下是堆栈分配的示例:
struct Foo {
int bar, baz
};
void foo(void) {
struct Foo f;
}
在堆栈上分配的对象仅在当前函数执行期间存在。当对的调用foo
超出范围时,变量也是如此f
。
成为问题的一种情况是,您需要从函数中返回除整数类型以外的其他内容(例如,上例中的Foo结构)。
例如,以下函数将导致所谓的“未定义行为”。
struct Foo {
int bar, baz
};
struct Foo *foo(void) {
struct Foo f;
return &f;
}
如果struct Foo *
要从函数返回类似的内容,则真正需要的是堆分配:
struct Foo {
int bar, baz
};
struct Foo *foo(void) {
return malloc(sizeof(struct Foo));
}
该函数malloc
在堆上分配一个对象,并返回指向该对象的指针。请注意,术语“对象”在这里被宽松地使用,意思是“某物”而不是面向对象编程的对象。
堆分配对象的生存期由程序员控制。该对象的内存将保留,直到程序员释放它为止,即通过调用free()
或直到程序退出。
编辑:我未能注意到此问题被标记为C ++问题。C ++运算符new
和new[]
执行与相同的功能malloc
。运算符delete
和delete[]
与相似free
。虽然new
和delete
应该专门用于分配和释放C ++对象,但在C ++代码中使用malloc
和free
完全合法。
用C编写任何不平凡的项目,您将必须弄清楚如何/何时使用指针。在C ++中,您将主要使用启用RAII的对象在内部管理指针,但在C中,原始指针的作用更为普遍。至于您应该做什么样的项目,它可以是任何不平凡的事情:
我推荐最后一个。
几乎可以使用指针解决的所有编程问题都可以使用其他更安全的引用类型解决(不是引用C ++引用,而是具有变量的通用CS概念引用存储在其他位置的数据值)。
指针是特定的底层引用实现,您可以在其中直接操作内存地址,功能非常强大,但使用起来可能会有些危险(例如,指向程序外部的内存位置)。
直接使用指针的好处是不必进行任何安全检查,它们的速度会稍快一些。像Java这样的语言不能直接实现C风格的指针,虽然性能会受到轻微的影响,但是会减少许多类型的难以调试的情况。
至于为什么需要间接访问,列表很长,但是本质上两个关键思想是:
selected_object
引用对象之一的变量比将当前对象的值复制到新变量中要有效得多。使用指针几乎总是更容易,更快地进行像素级图像操作。有时只能使用指针。
指针是C中任何数据结构实现的重要组成部分,而数据结构是任何非平凡程序的重要组成部分。
如果您想了解为什么指针如此重要,那么我建议您学习什么是链表,并尝试在不使用指针的情况下编写一个链表。我没有给您带来一个不可能的挑战,(提示:指针用于引用内存中的位置,如何引用数组中的内容?)。
仔细阅读各个StackExchange网站,我意识到提出这样的问题很时尚。坦率地说,冒着批评和不赞成投票的危险。这并不意味着拖延或发火,我仅是通过对问题的诚实评估来提供帮助。
评估如下:这是C程序员要问的一个非常奇怪的问题。它说的几乎都是“我不知道C”。如果我更加愤世嫉俗地进行分析,则有一个跟进此“问题”的暗示:“我是否可以采取一些捷径来快速而突然地获得经验丰富的C程序员的知识,而无需花费任何时间进行独立学习?” 某人可以给出的任何“答案”都不能代替他去做并了解潜在的概念及其用法。
我觉得直接学习C比在网上问这个问题更具建设性。当您很好地了解C时,您就不会再问这样的问题了,就像在问“用牙刷最好地解决什么问题?”。
即使在处理大型内存对象时指针确实发光,但是如果没有它们,仍然有一种方法可以做到这一点。
指针对于所谓的动态编程绝对必不可少,这是在您不知道程序执行之前需要多少内存的时候。在动态编程中,您可以在运行时请求内存块并将自己的数据放入其中-因此,您需要指针或引用(此处的区别并不重要)才能使用这些数据块。
只要您可以在运行时声明某些内存并将数据放入新获取的内存中,就可以执行以下操作:
您可以具有自扩展数据结构。这些结构可以通过声明额外的内存来扩展自身,只要它们的容量用完即可。每个自扩展结构的关键属性是它由小的存储块(取决于结构,称为节点,列表项等)组成,并且每个块都包含对其他块的引用。这种“链接”结构构建了大多数现代数据类型:图形,树,列表等。
您可以使用OOP(面向对象编程)范例进行编程。整个OOP都不基于使用直接变量,而是基于对类实例(称为对象)的引用并对其进行操作。没有指针就不能存在单个实例(即使即使没有指针也可以使用纯静态类,这是一个例外)。
有趣的是,我只是回答了有关C ++的问题,并谈到了指针。
简短的版本是您永远不需要指针,除非1)您正在使用的库强制您2)您需要可为空的引用。
如果需要数组,列表,字符串等,只需将其放在堆栈上并使用stl对象即可。返回或传递的stl对象是快速的(未经检查的事实),因为它们具有内部代码,该内部代码复制指针而不是对象,并且仅当您写入数据时才复制数据。这是常规C ++,甚至不是新的C ++ 11,这将使库编写者更容易使用它。
如果确实使用了指针,请确保其处于以下两种情况之一。1)您正在传递可能为空的输入。一个示例是可选的文件名。2)如果您想放弃所有权。就像传递或返回指针一样,您将没有剩余的任何副本,也不会使用您放弃的指针
ptr=blah; func(ptr); //never use ptr again for here on out.
但是我已经很长时间没有使用指针或智能指针了,因此我已经介绍了我的应用程序。它运行非常快。
其他说明:我注意到我确实编写了自己的结构,并且确实将它们传递了出去。那么,如何在不使用指针的情况下做到这一点呢?它不是STL容器,因此通过ref传递很慢。我总是加载我的数据列表/双端队列/地图等。我不记得返回任何对象,除非它是某种列表/映射。甚至没有字符串。我查看了单个对象的代码,然后注意到我做了类似的事情,{ MyStruct v; func(v, someinput); ... } void func(MyStruct&v, const D&someinput) { fillV; }
所以我几乎返回了对象(多个)或预分配/传递了填充参考(单个)。
现在,如果您正在编写自己的双端队列,地图等,则需要使用指针。但是您不需要。让STL并可能加剧对此的担忧。您只需要编写数据和解决方案。不是用来存放它们的容器;)
希望您现在不再使用指针:D。祝你好运与libs处理,迫使你
由于您的问题被标记为C ++,因此我将针对该语言回答您的问题。
在C ++中,指针和引用之间是有区别的,因此在两种情况下,必须使用指针(或智能指针)来促进某些行为。它们可以在其他情况下使用,但是您会问“如何最好地使用它们”,在所有其他情况下,都有更好的选择。
基类指针允许您调用一个虚拟方法,该方法取决于指针所指向的对象的类型。
动态创建对象(在堆而不是堆栈上)时,指针是必需的。当您希望对象的生存期长于创建对象的范围时,这是必需的。
正如其他人已经在这里所说的那样,在“好的项目或要解决的问题”方面,任何不重要的项目都将使用指针。