首页 文章

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

提问于
浏览
7

我刚从大学毕业,现在已经在C工作了一段时间 . 我理解C的所有基础知识并使用它们,但我很难掌握指针和类等更高级的主题 . 我已经阅读了一些书籍和教程,我理解其中的例子,但是当我看到一些高级的现实生活中的例子时,我无法弄明白 . 这让我很伤心,因为我觉得它让我无法将我的C编程提升到一个新的水平 . 有没有人有这个问题?如果是这样,你是如何突破它的?有没有人知道任何真正描述指针和类概念的书籍或教程?或者使用高级指针和类技术的一些示例代码具有良好的描述性注释?任何帮助将不胜感激 .

27 回答

  • 1

    理解C / C中的指针

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

    存储器地址通常称为变量的左值,存储的数据值称为rvalue(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的rvalue . 因此,我们告诉编译器xptr“指向”x .

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

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

    下一个难题是“间接运算符”('*'),其使用方法如下:

    int y = *xptr;
    

    间接运算符告诉程序将xptr的rval解释为内存地址而不是数据值 . 也就是说,程序查找存储在由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'具有相同的值所示 .

  • 0

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

    对我来说,当我开始用箭头绘制框时,指针会凝固 . 为int画一个框 . 而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书籍感到满意 .

  • 0

    This link有一个描述指针如何工作的视频,以及claymation . 信息丰富,易于消化 .

    This page有一些关于 class 基础的好信息 .

  • 4

    我曾经有一个问题,以pascal的方式理解指针:)一旦我开始做汇编指针真的是访问内存的唯一方法,它只是打我 . 这可能听起来像是一个远远的镜头,但尝试汇编(这总是一个好主意尝试和了解计算机的真正含义)可能会教你指点 . 课程 - 我不明白你的问题 - 你的学校是纯粹的结构化编程吗?一个类只是查看现实生活模型的逻辑方式 - 您正在尝试解决可以在许多对象/类中总结的问题 .

  • 18

    指针和类是完全不同的主题,所以我不会像这样把它们整合在一起 . 在这两个中,我会说指针更为基础 .

    了解指针的一个很好的练习如下:

    • 创建一个链表

    • 从头到尾迭代它

    • 将它反转,使得头部现在是背部,背部现在是头部

    首先在白板上完成所有操作 . 如果你可以轻松地做到这一点,你应该没有更多的问题来理解指针是什么 .

  • 2

    在其他答案中,指针似乎已被解决(没有双关语) .

    类是OO的基础 . 我遇到了巨大的麻烦,让我陷入OO - 就像十年失败的尝试一样 . 最终帮助我的书是Craig Larman的“应用UML和模式” . 我知道这听起来好像是关于某些不同的东西,但它真的很能让你轻松进入类和对象的世界 .

  • 0

    我们只是在午餐时讨论C和OO的一些方面,有人(实际上是一位伟大的工程师)说,除非你在学习C之前有一个非常强大的编程背景,否则它将彻底毁掉你 .

    我强烈建议先学习另一种语言,然后在需要时转换到C.它并不像指针有什么好处,它们只是一个残留的遗留物,当编译器很难在没有它们的情况下有效地组装转换操作 .

    这些天如果编译器无法更好地优化数组操作,那么你可以使用指针,你的编译器就会崩溃 .

    请不要误会我的意思,我不是说C很恐怖或者什么也不想开始进行宣传讨论,我现在偶尔使用它,我只是建议你先从别的东西开始 .

    这真的不像学习驾驶手动汽车然后轻松地将其应用到自动驾驶汽车,更像是学习驾驶这些巨大的建筑起重机,然后假设当你开始驾驶汽车时适用 - 然后你发现自己驾驶汽车在街道中央以5英里/小时的速度开启应急灯 .

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

  • 0

    要理解指针,我不能足够推荐K&R书 .

  • 0

    对于指针:

    我发现this post对指针进行了非常深思熟虑的讨论 . 也许这会有所帮助 . 您是否熟悉C#等引用?这实际上是指其他什么东西?这可能是理解指针的良好开端 .

    另外,请看下面肯特弗雷德里克的帖子,以另一种方式介绍自己的指针 .

  • 7

    学习汇编语言,然后学习C.然后你就会知道机器的基本原理是什么(以及前面的指针) .

    指针和类是C的基本方面 . 如果你不理解它们,那就意味着你并不真正理解C.

    就个人而言,我在C上停留了好几年,直到我觉得我已经牢牢掌握了C语言以及汇编语言中引发的内容 . 虽然这已经很久很久以前了,但我认为理解计算机在低级别工作的方式确实对我的职业生涯有所帮助 .

    学习编程可能需要很多年,但你应该坚持下去,因为这是一个非常有益的职业 .

  • 1

    练习没有替代品 .

    通过阅读书籍或听讲座很容易,感觉你正在追踪正在发生的事情 .

    我建议采取一些代码示例(我假设你在磁盘上的某些地方),编译它们并运行它们,然后尝试更改它们以做一些不同的事情 .

    • 将另一个子类添加到层次结构中

    • 将方法添加到现有类

    • 更改一个向前迭代通过集合的算法,然后返回 .

    我认为没有任何“银弹”书可以做到这一点 .

    对我来说,是什么驱动回家的指针在装配中起作用,并且看到指针实际上只是一个地址,并且指针并不意味着它指向的是一个有意义的对象

  • 0

    在类的情况下,我有三种技术真正帮助我跳转到真正的面向对象编程 .

    第一个是我参与了一个大量使用类和对象的游戏项目,大量使用泛化(种类或是一种关系,例如学生是一种人)和构成(有关系,例如,学生有学生贷款) . 打破这段代码需要做很多工作,但确实让事情变得透彻 .

    第二件事就是在我的System Analysis类中,我必须制作http://www.agilemodeling.com/artifacts/classDiagram.htm"> UML类图 . 这些我真的找到了帮助我理解类的结构在一个程序中 .

    最后,我帮助在我的大学辅导学生编程 . 我真正能说的就是你通过教学和看到别人对问题的处理方法来学到很多东西 . 很多时候,学生会尝试一些我从未想过的东西,但通常很有意义,他们只是在实现他们的想法时遇到了问题 .

    我最好的建议是需要大量的练习,你编程的越多,你就会越了解它 .

  • 1

    我读过的关于这些主题的最好的书是布鲁斯·埃克尔的思考 . 你可以免费下载here .

  • 19

    对于课程:

    对我而言,这个突破性的时刻就是我学习界面的时候 . 抽象出你如何编写的细节解决问题的想法,以及只提供与 class 互动的方法列表是非常有见地的 .

    事实上,我的教授明确告诉我们,他会通过将我们的课程插入他的测试工具来评定我们的课程 . 评分将根据他给我们的要求以及程序是否崩溃来完成 .

    简而言之,类允许你包装功能并以更干净的方式调用它(大多数时候,总是有例外)

  • 0

    唐纳德·阿尔科克(Donald Alcock)为我提供了破解指针的书是Illustrating Ansi C . 它充满了手绘风格的框和箭头图,说明了指针,指针算术,数组,字符串函数等...

    显然它是一本'C'书,但对于核心基础而言,它很难被击败

  • 1

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

    看到面向对象的范例,如图形形式的继承,是一种非常强大的方法来掌握这个概念 .

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

  • 0

    从拉塞维克的回应到similar question on SO

    指针是一个概念,对于许多人来说,一开始可能会让人感到困惑,特别是在复制指针值并仍然引用相同的内存块时 . 我发现最好的比喻是将指针视为一张纸上有一个房屋地址,以及它作为实际房屋引用的内存块 . 因此可以很容易地解释各种操作:复制指针值,只需在新纸上写下地址链表,房子里的纸上有下一个房子的地址释放内存,拆除房屋和擦除地址内存泄漏,你丢失了一张纸,找不到房子释放内存,但保留一个(现在无效)参考,拆除房子,擦除其中一张纸,但另一张纸与旧地址在它上面,当你去地址时,你找不到房子,但你可能会发现类似于一个缓冲区溢出的废墟的东西,你移动的东西比你可能适合的房子更多,溢出到邻居的房子里

  • 3

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

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

    它的图形过于简单化,但在大多数情况下,只要你永远不想知道这个数字是什么,或者手工设置它就应该没问题 .

    当我理解C时,我有一些宏,我或多或少允许你使用指针,就像它们是内存中的数组索引一样 . 但是我早就失去了那段代码而且很久以前就被遗忘了 .

    我记得它始于

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

    而这本身并没有用 . 希望其他人可以扩展这种逻辑 .

  • 0

    课程相对容易掌握; OOP可能需要你很多年 . 亲身,直到去年,我还没有完全掌握真正的OOP . Smalltalk在大学里并不像应该的那样普遍存在,这太糟糕了 . 它真正推动了OOP关于对象交易消息的观点,而不是类是具有函数的自包含全局变量 .

    如果你真的不熟悉课程,那么这个概念可能需要一段时间才能掌握 . 当我第一次在10年级遇到它们时,直到我知道他们正在做什么并逐步完成代码并解释发生了什么,我才得到它 . 这就是我建议你尝试的 .

  • 1

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

    至于类,除了OO范例,我认为从低级二进制角度看类可能很有趣 . 在基本层面上,它们在这方面并不复杂 .

    如果您想更好地了解C对象模型下面的内容,可以阅读Inside the C++ Object Model .

  • 0

    我真正得到指针的地方是在FatMac上编码TurboPascal(大约在1984年左右) - 当时是原生的Mac语言 .

    Mac有一个奇怪的内存模型,当分配地址时,内存存储在堆上的指针中,但是本身的位置无法保证,而内存处理例程返回指针指针 - 称为句柄 . 因此,要访问分配的内存的任何部分,必须取消引用句柄两次 . 花了一段时间,但不断的练习最终将课程带回家 .

    Pascal的指针处理比C语言更容易掌握,其中语法对初学者没有帮助 . 如果你真的和真正理解C中的指针,那么你最好的选择可能是获得一个副本aa Pascal编译器并尝试在其中编写一些基本的指针代码(Pascal足够接近C,你将在几个小时内获得基础知识) . 链接列表等是一个不错的选择 . 一旦你对那些返回C的人感到满意并掌握了概念,你就会发现悬崖看起来并不那么陡峭 .

  • 0

    你读过Bjarne Stroustrup的The C Programming Language吗?他创造了C .

    C FAQ Lite也很好 .

  • 0

    对于指针和类,这是我的比喻 . 我会用一副纸牌 . 卡片组具有面值和类型(心脏中的9个,黑桃中的4个等) . 所以在我们的C类编程语言“Deck of Cards”中我们会说以下内容:

    HeartCard card = 4; // 4 of hearts!
    

    现在,你知道4颗心在哪里,因为在你的手中,你正拿着甲板,面朝上,它在顶部!因此,就剩下的牌而言,我们只会说心中的4个是开心的 . 所以,如果我问你在BEGINNING有什么牌,你会说,“当然是4个心!” . 好吧,你只是“指出”了卡片的位置 . 在我们的“Deck of Cards”编程语言中,您还可以说以下内容:

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

    现在,把你的牌组翻过来 . 背面现在是BEGINNING,你不知道卡是什么 . 但是,让我们说你可以随心所欲地制作它,因为你充满了魔力 . 让我们在“Deck of Cards”语言中做到这一点!

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

    好吧,MakeMyCard(“心中的十分之一”)是你在做你的魔法并且知道你想要指向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是什么......这是一张有 Value 和心灵的卡片!因此,我们将其归类为HeartCard . 每种语言都有类似的方式来定义或“分类”你想要的东西,但它们都有相同的概念!希望这有助于......

  • 0

    你可能会发现这很有启发性 . 顺便说一句,如果你认为你已经使用C编译器工作了've been 1772183 and have graduated in CS, you may have gone to a JavaSchool (I' .

    此外,只是为了得到hojou和nsanders的答案,指针对C来说非常重要 . 如果你不理解指针,那么你就不了解C的基础知识(顺便说一下,承认这个事实是理解C的开始) . 同样,如果你不理解类,那么你就不理解C(或OO for)的基础知识那件事) .

    对于指针,我认为用盒子绘图是个好主意,但在装配中工作也是一个好主意 . 我认为,任何使用相对寻址的指令都可以让你更快地理解指针 .

    至于类(以及更普遍的面向对象编程),我建议使用Stroustrups“The C Programming Language”最新版本 . 它不仅是规范的C参考材料,而且在很多其他方面也有相当多的材料,从基本的面向对象的类层次结构和继承一直到大型系统中的设计原则 . 这是一个非常好的阅读(如果不是一点点厚实和简洁的点) .

  • 2

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

    int a;

    并且编译器为'a'生成存储,您're practically saying that you'重新声明
    一个int,你想命名它的内存位置'a' .

    当你说:

    int * a;

    你声明一个可以保存int的内存位置的变量 . 就这么简单 . 另外,不要害怕指针算术,当你处理指针并考虑遍历内存地址时,总是要记住一个“内存映射” .

    C中的类只是定义抽象数据类型的一种方法 . 我建议阅读一本好的OOP书来理解这个概念,然后,如果你有兴趣,可以学习C编译器如何生成代码来模拟OOP . 但是这个知识会及时到来,如果你坚持C足够长的时间:)

  • 0

    从某种意义上说,你可以认为“指针”是软件中最基本的两种类型之一 - 另一种是“值”(或“数据”) - 存在于一个巨大的可唯一寻址的存储位置块中 . 想一想 . 对象和结构等在内存中并不存在,只有值和指针才能存在 . 实际上,指针也是一个值....内存地址的值,而后者又包含另一个值....依此类推 .

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

    当你“取消引用”intB指针时,你正在查看存储在intB内存中的地址,查找该位置,然后查看存储在那里的值(一个数字) .

    通常情况下,当人们忘记他们正在处理的是什么时,我会遇到困惑,因为他们使用“&”,“*”和“ - >”运算符 - 它是地址, Value 还是什么?您只需要关注内存地址只是位置这一事实,并且该值是存储在那里的二进制信息 .

  • 0

    你的问题似乎是C中的C核,而不是C本身 . 获得Kernighan&Ritchie(C编程语言) . 吸气吧 . 这是非常好的东西,是有史以来最好的编程语言书之一 .

相关问题