在C ++中,我无法掌握指针和类

时间:2020-03-06 14:23:14  来源:igfitidea点击:

我刚大学毕业,现在已经在C ++中工作了一段时间。我了解C ++的所有基础知识并使用它们,但是我很难掌握指针和类之类的高级主题。我已经阅读了一些书籍和教程,并且理解了其中的示例,但是当我看一些高级的现实生活中的示例时,我无法弄清楚它们。这很让我丧命,因为我感觉这使我无法将C ++编程带入新的高度。还有其他人有这个问题吗?如果是这样,我们是如何突破的?
有谁知道能真正很好地描述指针和类概念的书籍或者教程吗?
还是一些使用高级指针和类技术的具有良好描述性注释的示例代码?
任何帮助将不胜感激。

解决方案

假装一个指针是一个数组地址。

x = 500; // memory address for hello;
MEMORY[x] = "hello"; 
print  MEMORY[x];

它在图形上过于简化,但在大多数情况下,只要我们不希望知道该数字是什么或者手动设置该数字,就可以了。

当我了解C时,我有了一些宏,它们或者多或者少地允许我们使用指针,就像它们是内存中的数组索引一样。但是我早已丢失了该代码,也早已忘记了。

我记得它始于

#define MEMORY 0; 
#define MEMORYADDRESS( a ) *a;

它本身几乎没有用。希望其他人可以对此逻辑进行扩展。

对于指针:

我发现这篇文章对指针进行了非常周到的讨论。也许会有所帮助。我们是否熟悉C#中的引用?那实际上是指其他东西吗?那可能是理解指针的一个很好的开始。

另外,请参阅下面的Kent Fredric的帖子,这是向我们介绍指针的另一种方式。

我以前在以帕斯卡方式返回指针时曾经遇到一个问题:)一旦我开始进行汇编程序指针访问,这实际上是访问内存的唯一方法,它使我很吃力。听起来似乎很遥远,但是尝试一下汇编程序(尝试理解计算机的真正含义始终是个好主意)可能会教给我们指针。上课很好我不明白问题是我们在学校学习纯结构化编程吗?类只是查看我们要解决的现实模型的一种逻辑方法,该模型可以总结为许多对象/类。

为了理解指针,我不能对K&R本书推荐得足够高。

关于这些主题,我读过的最好的书是Bruce Eckel撰写的《 C ++中的思考》。我们可以在此处免费下载。

指针和类是完全不同的主题,因此我不会真正将它们像这样混在一起。在这两个之中,我要说的是指针是更基本的。

下面是学习什么是指针的一个很好的练习:

  • 创建一个链表
  • 从头到尾遍历它
  • 扭转它,以便头部现在是背面,而背面现在是头部

首先在白板上完成所有操作。如果我们可以轻松做到这一点,那么了解什么是指针就不会有更多问题了。

该链接有一段视频,描述了如何使用粘土化技术来工作指针。内容丰富,并且易于消化。

该页面上有一些关于类基础知识的很好的信息。

指针和类在C ++中并不是真正的高级主题。它们是非常基本的。

对我来说,当我开始用箭头绘制框时,指针会固化。画一个整数框。现在,int *是一个单独的框,带有指向int框的箭头。

所以:

int foo = 3;           // integer
int* bar = &foo;       // assigns the address of foo to my pointer bar

使用指针的框(条),我可以选择查看框内的地址。 (这是foo的内存地址)。或者,我可以操纵任何我要处理的地址。这种操作意味着我正在跟随那个箭头到整数(foo)。

*bar = 5;  // asterix means "dereference" (follow the arrow), foo is now 5
bar = 0;   // I just changed the address that bar points to

上课完全是另一个主题。有一些关于面向对象设计的书,但是对于我的头上初学者来说,我不知道有什么好书。我们可能对Java入门书籍有好运。

对于课程:

对我来说,最重要的时刻是当我了解接口时。抽象出编写方式的细节的想法解决了一个问题,仅给出与类进行交互的方法列表非常有见地。

实际上,我的教授明确地告诉我们,他将通过将课程插入他的测试工具来对我们的课程进行评分。将根据他给我们的要求以及程序是否崩溃来进行评分。

长话短说,类使我们可以包装功能并以更简洁的方式调用它(大多数情况下,总是有例外)

帮我指尖的那本书是唐纳德·阿尔考克(Donald Alcock)的《插图Ansi C》。它充满了手绘样式的方框图和箭头图,它们说明了指针,指针算术,数组,字符串函数等。

显然,它是一本" C"书,但对于核心基础知识来说,它很难被击败

真正帮助我理解这些概念的一件事是学习UML统一建模语言。以图形格式查看面向对象设计的概念确实有助于我了解它们的含义。有时,仅通过查看源代码实现这些概念来试图理解这些概念可能很难理解。

以图形形式查看诸如继承之类的面向对象范例是掌握该概念的一种非常有效的方法。

Martin Fowler的UML Distilled是一个很好的简短介绍。

从lassevek对SO的类似问题的回答:

Pointers is a concept that for many
  can be confusing at first, in
  particular when it comes to copying
  pointer values around and still
  referencing the same memory block.
  
  I've found that the best analogy is to
  consider the pointer as a piece of
  paper with a house address on it, and
  the memory block it references as the
  actual house. All sorts of operations
  can thus be easily explained:
  
  
  Copy pointer value, just write the address on a new piece of paper
  Linked lists, piece of paper at the house with the address of the next
  house on it
  Freeing the memory, demolish the house and erase the address
  Memory leak, you lose the piece of paper and cannot find the house
  Freeing the memory but keeping a (now invalid) reference, demolish the
  house, erase one of the pieces of
  paper but have another piece of paper
  with the old address on it, when you
  go to the address, you won't find a
  house, but you might find something
  that resembles the ruins of one
  Buffer overrun, you move more stuff into the house than you can
  possibly fit, spilling into the
  neighbours house

我认为,为了更好地理解指针,查看汇编语言如何与指针一起使用可能会很有用。指针的概念实际上是汇编语言和x86处理器指令体系结构的基本部分之一。就像指针是程序的自然组成部分一样,它可能会让我们失望。

关于类,除了OO范式之外,我认为从低级二进制的角度来看类可能会很有趣。从根本上讲,它们在这方面并不复杂。

如果我们想更好地了解C ++对象模型下面的内容,可以阅读《 C ++对象模型内部》。

指针似乎已经在其他答案中得到了解决(没有双关语)。

类是面向对象的基础。十年的失败尝试让我难以置信于OO。最终帮助我的那本书是Craig Larman的"应用UML和模式"。我知道这听起来好像是有些不同,但这确实使我们轻松进入类和对象的世界确实很棒。

我们只是在午餐时讨论C ++和OO的某些方面,有人(实际上是一位出色的工程师)在说,除非我们在学习C ++之前具有真正的编程背景,否则它确实会毁了我们。

我强烈建议我们先学习另一种语言,然后在需要时改用C ++。并不是说指针有什么大不了的,它们只是当编译器在没有它们的情况下很难将操作有效地转换为汇编时遗留下来的残余部分。

这些天,如果编译器不能更好地优化数组操作,那么我们可以使用指针,那么编译器就坏了。

请不要误会我的意思,我并不是说C ++太可怕了,也不希望开始倡导性讨论,我已经使用过它,现在偶尔使用它,我只是建议我们从其他角度开始。

这真的不像是学习驾驶手动汽车,然后轻松地将其应用于自动驾驶汽车,它更像是学习在那些大型建筑起重机之一上驾驶,然后假设当我们开始驾驶汽车时会应用这种汽车,然后发现自己的汽车以5英里/小时的速度在街道中央开着应急灯。

回顾最后一段-我认为这可能是我有史以来最准确的比喻!

学习汇编语言,然后学习C。然后,我们将了解机器的基本原理(以及前面的指针)。

指针和类是C ++的基本方面。如果我们不了解它们,则意味着我们并不真正了解C ++。

我个人坚持使用C ++几年,直到我对C以及对汇编语言的内幕发生了深刻的了解。尽管这已经是很长时间了,但我认为了解计算机在低层的工作方式确实使我的职业受益。

学习编程可能需要很多年,但是我们应该坚持学习,因为这是一项非常有意义的职业。

班级相对容易掌握; OOP可能会花费我们很多年。就个人而言,直到去年,我才完全掌握真正的面向对象操作。太糟糕了,Smalltalk在大学中没有得到应有的普及。它确实使人们认识到OOP是关于对象交换消息的,而不是类是带有函数的自包含全局变量。

如果我们确实是班上的新手,那么这个概念可能需要一段时间才能掌握。当我10年级第一次遇到他们时,直到有一个知道他们在做什么的人逐步了解代码并解释发生了什么时,我才知道。这就是我建议我们尝试的方法。

没有练习的替代品。

阅读本书或者听讲座很容易,就好像我们正在关注正在发生的事情。

我建议采取一些代码示例(假设我们将它们放在磁盘上的某个位置),编译并运行它们,然后尝试更改它们以执行其他操作。

  • 将另一个子类添加到层次结构
  • 将方法添加到现有类
  • 更改向前遍历集合的算法,然后向后遍历。

我认为没有任何"银弹"书可以做到这一点。

对我来说,指针的含义是在汇编中工作,并且看到指针实际上只是一个地址,而拥有指针并不意味着它所指向的对象是有意义的对象。

我真正得到的指点是在FatMac(大约1984年左右)上编码TurboPascal(当时是Mac的本地语言)。

Mac有一个奇数的内存模型,即当分配地址时,内存被存储在堆上的指针中,但是不能保证其本身的位置,而是由内存处理例程将指针返回到称为句柄的指针。因此,要访问分配的内存的任何部分,必须将句柄解除引用两次。花了一段时间,但不断的练习最终驱使这门课回家。

Pascal的指针处理比C ++更容易掌握,C ++的语法对初学者没有帮助。如果我们确实真正地了解了C中的指针,那么最好的选择可能是获取Pascal编译器的副本并尝试在其中编写一些基本的指针代码(Pascal与C足够接近,我们将在几小时内获得基本信息)。链接列表之类是一个不错的选择。一旦我们对那些回归C ++并熟悉了这些概念的内容感到满意,我们就会发现悬崖看起来不会那么陡峭。

从某种意义上讲,我们可以将"指针"视为软件中两个最基本的类型之一,另一个是存在于巨大的唯一可寻址内存位置块中的"值"(或者"数据")。想一想。对象和结构等实际上并不存在于内存中,只有值和指针存在。实际上,指针也是一个值...内存地址的值,该地址又包含另一个值...等等。

因此,在C / C ++中,当我们声明" int"(intA)时,我们将定义一个32位内存块,其中包含一个数字值。如果然后声明" int指针"(intB),则将定义一个包含int地址的32位内存块。我可以通过声明" intB =&intA"来指定后者指向前者,现在定义为intB的32位内存包含一个与intA在内存中位置相对应的地址。

当我们"取消引用" intB指针时,我们正在查看存储在intB内存中的地址,找到该位置,然后查看在此存储的值(一个数字)。

通常,当人们在使用"&"," *"和"->"运算符时无法确切了解正在处理的内容时,我会感到困惑。我们只需要关注以下事实:内存地址只是位置,而值是存储在此处的二进制信息。

我们读过Bjarne Stroustrup的C ++编程语言吗?他创建了C ++。

C ++ FAQ Lite也很好。

对于指针和类,这是我的类比。我将使用一副纸牌。一副纸牌具有面值和类型(9张红心,4张黑桃等)。因此,在类似于"纸牌"的C ++编程语言中,我们将说以下内容:

HeartCard card = 4; // 4 of hearts!

现在,我们知道四颗心在哪里,因为天哪,我们拿着甲板,面朝上,就在顶端!因此,对于其余的牌,我们只能说4个红心位于BEGINNING。因此,如果我问我们在BEGINNING上持什么牌,我们会说:"当然是4颗心!"。好吧,我们只是将我"指向"卡片的位置。在我们的"纸牌组"编程语言中,我们还可以说以下话:

HeartCard card = 4; // 4 of hearts!
print &card // the address is BEGINNING!

现在,将纸牌翻过来。现在背面开始了,我们不知道该卡是什么。但是,可以说我们可以随心所欲地制作它,因为我们充满了魔力。让我们在"卡片组"语言中执行此操作!

HeartCard *pointerToCard = MakeMyCard( "10 of hearts" );
print pointerToCard // the value of this is BEGINNING!
print *pointerToCard // this will be 10 of hearts!

好吧,MakeMyCard(" 10个心")是我们在做魔术并且知道我们要指向BEGINNING时,使该卡成为10个心!我们将卡翻转过来,瞧!现在,*可能会让我们失望。如果是这样,请检查以下内容:

HeartCard *pointerToCard = MakeMyCard( "10 of hearts" );
HeartCard card = 4; // 4 of hearts!
print *pointerToCard; // prints 10 of hearts
print pointerToCard; // prints BEGINNING
print card; // prints 4 of hearts
print &card; // prints END - the 4 of hearts used to be on top but we flipped over the deck!

至于类,我们在示例中通过将类型定义为HeartCard来使用类。我们知道HeartCard是什么……这是一张具有价值和心脏类型的卡片!因此,我们将其归类为HeartCard。每种语言都有类似的方式来定义或者"分类"我们想要的内容,但是它们都具有相同的概念!希望这可以帮助...

我们可能会发现Joel的这篇文章具有启发性。顺便说一句,如果我们"在C ++中工作了一段时间"并且毕业于CS,我们可能已经去过JavaSchool(我认为我们根本没有在C ++中工作;我们已经一直在C中工作,但使用的是C ++编译器)。

同样,仅次于hojou和nsanders的答案,指针对于C ++非常重要。如果我们不了解指针,那么我们将不了解C ++的基础知识(顺便说一句,认识到这一事实是了解C ++的开始)。同样,如果我们不了解类,那么我们将不了解C ++(或者OO)的基础知识。

对于指针,我认为带框绘图是个好主意,但在汇编中工作也是个好主意。我认为,任何使用相对寻址的指令都会使我们快速了解什么指针。

至于类(和更一般的面向对象程序设计),我建议使用最新版本的Stroustrups" C ++程序设计语言"。它不仅是规范的C ++参考资料,而且在许多其他方面也有很多资料,从基本的面向对象的类层次结构和继承一直到大型系统的设计原理。这是一本很好的读物(如果不是有点浓密和简洁)。

了解C / C ++中的指针

在理解指针如何工作之前,有必要了解变量在程序中的存储和访问方式。每个变量都有两个部分:(1)存储数据的存储地址和(2)存储的数据的值。

内存地址通常称为变量的左值,而存储的数据的值称为右值(l和r表示左右)。

考虑以下语句:

int x = 10;

在内部,程序将内存地址与变量x关联。在这种情况下,我们假设程序将x分配为驻留在地址1001(不是实际地址,而是为简单起见而选择)中。因此,x的左值(内存地址)为1001,x的右值(数据值)为10.

只需使用变量x即可访问右值。为了访问左值,需要运算符(&)的地址。表达式&x读作" x的地址"。

Expression          Value
----------------------------------
x                   10
&x                  1001

x中存储的值可以随时更改(例如x = 20),但是x(&x)的地址永远不能更改。

指针只是一个变量,可以用来修改另一个变量。它通过为其右值设置一个内存地址来实现此目的。也就是说,它指向内存中的另一个位置。

创建指向x的指针的操作如下:

int* xptr = &x;

int *告诉编译器我们正在创建一个指向整数值的指针。 =&x部分告诉编译器我们正在将x的地址分配给xptr的右值。因此,我们告诉编译器xptr指向x。

假设xptr被分配了1002的内存地址,则程序的内存可能如下所示:

Variable    lvalue    rvalue
--------------------------------------------
x           1001      10   
xptr        1002      1001

下一个难题是"间接运算符"(*),其用法如下:

int y = *xptr;

间接运算符告诉程序将xptr的右值解释为内存地址而不是数据值。即,程序寻找在xptr(1001)提供的地址处存储的数据值(10)。

放在一起:

Expression      Value
--------------------------------------------
x                   10
&x                  1001
xptr                1001
&xptr               1002
*xptr               10

现在已经解释了这些概念,下面是一些代码来演示指针的功能:

int x = 10;
int *xptr = &x;

printf("x = %d\n", x);
printf("&x = %d\n", &x);        
printf("xptr = %d\n", xptr);
printf("*xptr = %d\n", *xptr);

*xptr = 20;

printf("x = %d\n", x);
printf("*xptr = %d\n", *xptr);

对于输出,我们会看到(注意:每次的内存地址都会不同):

x = 10
&x = 3537176
xptr = 3537176
*xptr = 10
x = 20
*xptr = 20

请注意,为* xptr分配值是如何更改x的值的。这是因为* xptr和x指向内存中的相同位置,这由&x和xptr具有相同的值来证明。

指针不是某种神奇的东西,我们一直在使用它们!
当你说:

诠释

并且编译器为" a"生成存储,实际上我们是在声明
一个int,并且我们想将其存储位置命名为" a"。

当你说:

int * a;

我们在声明一个可以保存int内存位置的变量。
就这么简单。另外,不要害怕指针运算,只是总是
当我们处理指针并以术语方式思考时,请牢记"内存映射"
遍历内存地址的过程。

C ++中的类只是定义抽象数据类型的一种方法。我建议我们阅读一本很好的OOP书籍来理解这一概念,然后,如果我们感兴趣的话,请学习C ++编译器如何生成代码来模拟OOP。但是,如果我们坚持使用C ++足够长的时间,那么这些知识就会及时出现:)

问题似乎是C ++中的C核心,而不是C ++本身。让自己成为Kernighan&Ritchie(C编程语言)。吸气这是非常好的东西,是有史以来最好的编程语言书籍之一。

对于类,我拥有三种技术,这些技术确实帮助我进入了真正的面向对象编程。

首先是我从事一个游戏项目,该项目大量使用类和对象,大量使用泛化(种类或者is-关系,例如学生是一种人)和构图(具有-关系,前学生有学生贷款)。分解该代码需要花费大量工作,但确实使事情变得有意义。

第二件事是在我的系统分析类中,我必须制作http://www.agilemodeling.com/artifacts/classDiagram.htm">UML类图,这些才真正帮助我理解了类的结构在一个程序中。

最后,我帮助学院的补习生进行编程。我只能说的是,我们通过学习和观察他人解决问题的方法学到了很多东西。很多时候,一个学生会尝试一些我从未想过的事情,但通常会很有道理,他们在实现自己的想法时遇到问题。

我最好的建议是,它需要大量练习,而我们编写的程序越多,我们就会越了解它。