C语言 人们对 C 指针有什么困难?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4025768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:48:58  来源:igfitidea点击:

What do people find difficult about C pointers?

cpointers

提问by The Archetypal Paul

From the number of questions posted here, it's clear that people have some pretty fundemental issues when getting their heads around pointers and pointer arithmetic.

从这里发布的问题数量来看,很明显人们在处理指针和指针运算时会遇到一些非常基本的问题。

I'm curious to know why. They've never really caused me major problems (although I first learned about them back in the Neolithic). In order to write better answers to these questions, I'd like to know what people find difficult.

我很想知道为什么。它们从未真正给我带来过重大问题(尽管我是在新石器时代第一次了解到它们的)。为了更好地回答这些问题,我想知道人们觉得困难的地方。

So, if you're struggling with pointers, or you recently were but suddenly "got it", what were the aspects of pointers that caused you problems?

那么,如果您正在为指针而苦苦挣扎,或者您最近突然“明白了”,那么指针的哪些方面给您带来了问题?

采纳答案by jkerian

I suspect people are going a bit too deep in their answers. An understanding of scheduling, actual CPU operations, or assembly-level memory management isn't really required.

我怀疑人们在他们的答案中走得太深了。真正需要了解调度、实际 CPU 操作或程序集级内存管理。

When I was teaching, I found the following holes in students' understanding to be the most common source of problems:

在教学中,我发现以下学生理解上的漏洞是最常见的问题来源:

  1. Heap vs Stack storage. It is simply stunning how many people do not understand this, even in a general sense.
  2. Stack frames. Just the general concept of a dedicated section of the stack for local variables, along with the reason it's a 'stack'... details such as stashing the return location, exception handler details, and previous registers can safely be left till someone tries to build a compiler.
  3. "Memory is memory is memory" Casting just changes which versions of operators or how much room the compiler gives for a particular chunk of memory. You know you're dealing with this problem when people talk about "what (primitive) variable X reallyis".
  1. 堆与堆栈存储。令人震惊的是,即使在一般意义上,有多少人也不理解这一点。
  2. 堆栈帧。只是用于局部变量的堆栈的专用部分的一般概念,以及它是“堆栈”的原因……诸如隐藏返回位置、异常处理程序详细信息和以前的寄存器之类的细节可以安全地留待有人​​尝试构建编译器。
  3. “内存就是内存就是内存” Casting 只是改变了运算符的版本或编译器为特定内存块提供了多少空间。你知道你处理这个问题,当人们谈论“什么(基本)变量X真的是”。

Most of my students were able to understand a simplified drawing of a chunk of memory, generally the local variables section of the stack at the current scope. Generally giving explicit fictional addresses to the various locations helped.

我的大多数学生都能够理解一块内存的简化图,通常是当前范围内堆栈的局部变量部分。通常为各个位置提供明确的虚构地址有帮助。

I guess in summary, I'm saying that if you want to understand pointers, you have to understand variables, and what they actually are in modern architectures.

我想总而言之,我是说如果你想理解指针,你必须理解变量,以及它们在现代架构中的实际含义。

回答by Jeff Knecht

When I first started working with them, the biggest problem I had was the syntax.

当我第一次开始使用它们时,我遇到的最大问题是语法。

int* ip;
int * ip;
int *ip;

are all the same.

都是一样的。

but:

但:

int* ip1, ip2;  //second one isn't a pointer!
int *ip1, *ip2;

Why? because the "pointer" part of the declaration belongs to the variable, and not the type.

为什么?因为声明的“指针”部分属于变量,而不是类型。

And then dereferencing the thing uses a very similar notation:

然后取消引用事物使用非常相似的符号:

*ip = 4;  //sets the value of the thing pointed to by ip to '4'
x = ip;   //hey, that's not '4'!
x = *ip;  //ahh... there's that '4'

Except when you actually need to get a pointer... then you use an ampersand!

除非你真的需要得到一个指针......然后你使用一个&符号!

int *ip = &x;

Hooray for consistency!

为一致性万岁!

Then, apparently just to be jerks and prove how clever they are, a lot of library developers use pointers-to-pointers-to-pointers, and if they expect an array of those things, well why not just pass a pointer to that too.

然后,显然只是为了成为混蛋并证明他们有多聪明,许多库开发人员使用指向指针的指针,如果他们期望这些东西的数组,那么为什么不直接传递一个指针呢? .

void foo(****ipppArr);

to call this, I need the address of the array of pointers to pointers to pointers of ints:

要调用它,我需要指向 int 指针的指针数组的地址:

foo(&(***ipppArr));

In six months, when I have to maintain this code, I will spend more time trying to figure out what all this means than rewriting from the ground up. (yeah, probably got that syntax wrong -- it's been a while since I've done anything in C. I kinda miss it, but then I'm a bit of a massochist)

六个月后,当我必须维护这段代码时,我会花更多的时间试图弄清楚这一切意味着什么,而不是从头开始重写。(是的,可能语法错误——我已经有一段时间没有用 C 做过任何事情了。我有点想念它,但后来我有点受虐狂)

回答by Robert Harvey

Proper understanding of pointers requires knowledge about the underlying machine's architecture.

正确理解指针需要了解底层机器的架构。

Many programmers today don't know how their machine works, just as most people who know how to drive a car don't know anything about the engine.

今天的许多程序员不知道他们的机器是如何工作的,就像大多数知道如何驾驶汽车的人对引擎一无所知一样。

回答by David Titarenco

When dealing with pointers, people that get confused are widely in one of two camps. I've been (am?) in both.

在处理指针时,感到困惑的人广泛地处于两个阵营之一。我一直(是?)在这两个。

The array[]crowd

array[]人群

This is the crowd that straight up doesn't know how to translate from pointer notation to array notation (or doesn't even know that they are even related). Here are four ways to access elements of an array:

这是一群直接不知道如何从指针表示法转换为数组表示法(或者甚至不知道它们是相关的)的人群。以下是访问数组元素的四种方法:

  1. array notation (indexing) with the array name
  2. array notation (indexing) with the pointer name
  3. pointer notation (the *) with the pointer name
  4. pointer notation (the *) with the array name
  1. 带有数组名称的数组符号(索引)
  2. 带有指针名称的数组符号(索引)
  3. 带有指针名称的指针符号(*)
  4. 带有数组名称的指针符号(*)

 

 

int vals[5] = {10, 20, 30, 40, 50};
int *ptr;
ptr = vals;

array       element            pointer
notation    number     vals    notation

vals[0]     0          10      *(ptr + 0)
ptr[0]                         *(vals + 0)

vals[1]     1          20      *(ptr + 1)
ptr[1]                         *(vals + 1)

vals[2]     2          30      *(ptr + 2)
ptr[2]                         *(vals + 2)

vals[3]     3          40      *(ptr + 3)
ptr[3]                         *(vals + 3)

vals[4]     4          50      *(ptr + 4)
ptr[4]                         *(vals + 4)

The idea here is that accessing arrays via pointers seemspretty simple and straightforward, but a ton of very complicated and clever things can be done this way. Some of which can leave experienced C/C++ programmers befuddled, let alone inexperienced newbies.

这里的想法是通过指针访问数组看起来非常简单和直接,但是可以通过这种方式完成大量非常复杂和聪明的事情。其中一些可能会让有经验的 C/C++ 程序员感到困惑,更不用说没有经验的新手了。

The reference to a pointerand pointer to a pointercrowd

reference to a pointerpointer to a pointer人群

Thisis a great article that explains the difference and which I'll be citing and stealing some code from :)

是一篇很棒的文章,它解释了差异,我将引用并从中窃取一些代码:)

As a small example, it can be very difficult to see exactly what the author wanted to do if you came across something like this:

作为一个小例子,如果你遇到这样的事情,就很难确切地看到作者想要做什么:

//function prototype
void func(int*& rpInt); // I mean, seriously, int*& ??

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(pvar);
  ....
  return 0;
}

Or, to a lesser extent, something like this:

或者,在较小程度上,是这样的:

//function prototype
void func(int** ppInt);

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(&pvar);
  ....
  return 0;
}

So at the end of the day, what do we really solve with all this gibberish? Nothing.

那么在一天结束时,我们用这些胡言乱语真正解决了什么问题?没有。

Now we have seen the syntax of ptr-to-ptr and ref-to-ptr. Are there any advantages of one over the other? I am afraid, no. The usage of one of both, for some programmers are just personal preferences. Some who use ref-to-ptr say the syntax is "cleaner" while some who use ptr-to-ptr, say ptr-to-ptr syntax makes it clearer to those reading what you are doing.

现在我们已经看到了 ptr-to-ptr 和 ref-to-ptr 的语法。一个比另一个有什么优势吗?恐怕,没有。两者之一的用法,对于一些程序员来说只是个人喜好。一些使用 ref-to-ptr 的人说语法“更清晰”,而一些使用 ptr-to-ptr 的人说 ptr-to-ptr 语法让那些阅读你正在做的事情的人更清楚。

This complexity and the seeming(bold seeming) interchangeability with references ,which is often another caveat of pointers and an error of newcomers, makes understanding pointers hard. It's also important to understand, for completion's sake, that pointers to references are illegal in C and C++ for confusing reasons that take you into lvalue-rvaluesemantics.

这种复杂性和与引用的表面(粗体)互换性,这通常是指针的另一个警告和新手的错误,使得理解指针变得困难。同样重要的是要理解,为了完成,指向引用的指针在 C 和 C++ 中是非法的,因为令人困惑的原因让你陷入lvalue-rvalue语义。

As a previous answer remarked, many times you'll just have these hotshot programmers that think they are being clever by using ******awesome_var->lol_im_so_clever()and most of us are probably guilty of writing such atrocities at times, but it's just not good code, and it's certainly not maintainable.

正如之前的回答所说,很多时候你只会让这些炙手可热的程序员认为他们很聪明******awesome_var->lol_im_so_clever(),我们中的大多数人有时可能会犯下这样的暴行,但这不是好的代码,而且肯定是不可维护的.

Well this answer turned out to be longer than I had hoped...

好吧,结果证明这个答案比我希望的要长......

回答by John Bode

I blame the quality of reference materials and the people doing the teaching, personally; most concepts in C (but especiallypointers) are just plain taughtbadly. I keep threatening to write my own C book (titled The Last Thing The World Needs Is Another Book On The C Programming Language), but I don't have the time or the patience to do so. So I hang out here and throw random quotes from the Standard at people.

我个人责怪参考资料的质量和教学人员;C 中的大多数概念(尤其是指针)都得不好。我一直威胁要写我自己的 C 书(名为The Last Thing The Last Thing Is another Book On The C Programming Language),但我没有时间或耐心这样做。所以我在这里闲逛,向人们抛出标准中的随机引述。

There's also the fact that when C was initially designed, it was assumedyou understood machine architecture to a pretty detailed level just because there was no way to avoid it in your day-to-day work (memory was so tight and processors were so slow you had to understand how what you wrote affected performance).

还有一个事实是,在最初设计 C 时,假设您非常详细地了解机器架构,因为在您的日常工作中无法避免它(内存非常紧张,处理器非常慢)您必须了解您编写的内容如何影响性能)。

回答by Steve Townsend

There is a great article supporting the notion that pointers are hard on Joel Spolsky's site - The Perils of JavaSchools.

在 Joel Spolsky 的网站上有一篇很棒的文章支持指针很难的观点 - JavaSchools 的危险

[Disclaimer - I am not a Java-hater per se.]

[免责声明 - 我本身并不是一个讨厌 Java 的。]

回答by Mike Dunlavey

Most things are harder to understand if you're not grounded in the knowledge that's "underneath". When I taught CS it got a lot easier when I started my students on programming a very simple "machine", a simulated decimal computer with decimal opcodes whose memory consisted of decimal registers and decimal addresses. They would put in very short programs to, for example, add a series of numbers to get a total. Then they would single step it to watch what was happening. They could hold down the "enter" key and watch it run "fast".

如果您不以“底层”知识为基础,大多数事情都更难理解。当我教 CS 时,当我让我的学生开始编写一个非常简单的“机器”时,它变得容易多了,这是一台模拟十进制计算机,带有十进制操作码,其内存由十进制寄存器和十进制地址组成。他们会编写非常短的程序,例如,将一系列数字相加以获得总数。然后他们会单步执行它以观察正在发生的事情。他们可以按住“回车”键,看着它“快速”运行。

I'm sure almost everyone on SO wonders why it is useful to get so basic. We forget what it was like not knowing how to program. Playing with such a toy computer puts in place concepts without which you can't program, such as the ideas that computation is a step-by-step process, using a small number of basic primitives to build up programs, and the concept of memory variables as places where numbers are stored, in which the address or name of the variable is distinct from the number it contains. There is a distinction between the time at which you enter the program, and the time at which it "runs". I liken learning to program as crossing a series of "speed bumps", such as very simple programs, then loops and subroutines, then arrays, then sequential I/O, then pointers and data structure. All of these are much easier to learn by reference to what a computer is really doing underneath.

我敢肯定,SO 上的几乎每个人都想知道为什么获得如此基本的知识很有用。我们忘记了不知道如何编程是什么感觉。玩这样的玩具电脑,你就无法编程,比如计算是一个循序渐进的过程,使用少量的基本原语来构建程序,以及内存的概念。变量作为存储数字的地方,其中变量的地址或名称与其包含的数字不同。进入程序的时间和它“运行”的时间是有区别的。我将学习编程比作跨越一系列“减速带”,例如非常简单的程序,然后是循环和子例程,然后是数组,然后是顺序 I/O,然后是指针和数据结构。

Finally, when getting to C, pointers are confusing though K&R did a very good job of explaining them. The way I learned them in C was to know how to read them - right to left. Like when I see int *pin my head I say "ppoints to an int". C was invented as one step up from assembly language and that's what I like about it - it is close to that "ground". Pointers, like anything else, are harder to understand if you don't have that grounding.

最后,在使用 C 语言时,虽然 K&R 很好地解释了指针,但它们令人困惑。我在 C 中学习它们的方式是知道如何阅读它们——从右到左。就像当我int *p在脑海中看到时,我说“p指向一个int”。C 是作为汇编语言的一个进步而被发明的,这就是我喜欢它的地方 - 它接近那个“基础”。指针,就像其他任何东西一样,如果你没有那个基础,就更难理解。

回答by J. Polfer

I didn't get pointers until I read the description in K&R. Until that point, pointers didn't make sense. I read a whole bunch of stuff where people said "Don't learn pointers, they are confusing and will hurt your head and give you aneurysms" so I shied away from it for a long time, and created this unnecessary air of difficult-concept.

在我阅读 K&R 中的描述之前,我没有得到指示。在那之前,指针没有任何意义。我读了一大堆东西,人们说“不要学习指针,它们令人困惑,会伤到你的头并给你带来动脉瘤”,所以我很长一段时间都避开它,并创造了这种不必要的困难概念的气氛.

Otherwise, mostly what I thought was, why on earth would you want a variable that you have to go through hoops to get the value of, and if you wanted to assign stuff to it, you had to do strange things to get values to go into them. The whole point of a variable is something to store a value, I thought, so why someone wanted to make it complicated was beyond me. "So with a pointer you have to use the *operator to get at its value??? What kind of goofy variable is that?", I thought. Pointless, no pun intended.

否则,主要是我的想法是,你到底为什么想要一个变量,你必须通过箍来获取它的值,如果你想给它赋值,你必须做一些奇怪的事情来获取值进入他们。我想,变量的全部意义在于存储值,所以为什么有人想让它变得复杂,我无法理解。 “所以对于一个指针,你必须使用*运算符来获取它的值?这是什么类型的愚蠢变量?” , 我想。毫无意义,没有双关语的意思。

The reason it was complicated was because I didn't understand that a pointer was an addressto something. If you explain that it is an address, that it is something that contains an address to something else, and that you can manipulate that address to do useful things, I think it might clear up the confusion.

它之所以复杂是因为我不明白指针是指向某物的地址。如果你解释说它是一个地址,它包含一个指向其他东西的地址,并且你可以操纵该地址来做有用的事情,我认为这可能会消除混淆。

A class that required using pointers to access/modify ports on a PC, using pointer arithmetic to address different memory locations, and looking at more complicated C-code that modified their arguments disabused me of the idea that pointers were, well, pointless.

一个类需要使用指针来访问/修改 PC 上的端口,使用指针算术来寻址不同的内存位置,以及查看更复杂的 C 代码来修改它们的参数,这让我不相信指针是毫无意义的。

回答by Andrew Cottrell

Here's a pointer/array example that gave me pause. Assume you have two arrays:

这是一个让我暂停的指针/数组示例。假设你有两个数组:

uint8_t source[16] = { /* some initialization values here */ };
uint8_t destination[16];

And your goal is to copy the uint8_t contents from source destination using memcpy(). Guess which of the following accomplish that goal:

您的目标是使用 memcpy() 从源目标复制 uint8_t 内容。猜猜以下哪项可以实现该目标:

memcpy(destination, source, sizeof(source));
memcpy(&destination, source, sizeof(source));
memcpy(&destination[0], source, sizeof(source));
memcpy(destination, &source, sizeof(source));
memcpy(&destination, &source, sizeof(source));
memcpy(&destination[0], &source, sizeof(source));
memcpy(destination, &source[0], sizeof(source));
memcpy(&destination, &source[0], sizeof(source));
memcpy(&destination[0], &source[0], sizeof(source));

The answer (Spoiler Alert!) is ALL of them. "destination", "&destination", and "&destination[0]" are all the same value. "&destination" is a different typethan the other two, but it is still the same value. The same goes for the permutations of "source".

答案(剧透警报!)就是所有这些。“destination”、“&destination”和“&destination[0]”都是相同的值。"&destination"与其他两个类型不同,但它仍然是相同的值。“源”的排列也是如此。

As an aside, I personally prefer the first version.

顺便说一句,我个人更喜欢第一个版本。

回答by nategoose

I should start out by saying that C and C++ were the first programming languages I learned. I started with C, then did C++ in school, a lot, and then went back to C to become fluent in it.

我应该首先说 C ​​和 C++ 是我学习的第一门编程语言。我从 C 开始,然后在学校做了 C++,很多,然后回到 C 变得流利。

The first thing that confused me about pointers when learning C was the simple:

在学习 C 时,让我对指针感到困惑的第一件事很简单:

char ch;
char str[100];
scanf("%c %s", &ch, str);

This confusion was mostly rooted in having been introduced to using reference to a variable for OUT arguments before pointers were properly introduced to me. I remember that I skipped writing the first few examples in CforDummiesbecause they were too simple only to never get the first program I did write to work (most likely because of this).

这种混淆主要是因为在正确地向我引入指针之前,已经引入了对 OUT 参数的变量的引用。我记得我跳过用C for Dummies编写前几个例子,因为它们太简单了,只是无法让我编写的第一个程序运行(很可能是因为这个)。

What was confusing about this was what &chactually meant as well as why strdidn't need it.

令人困惑的是这&ch实际上意味着什么以及为什么str不需要它。

After I became familiar with that I next remember being confused about dynamic allocation. I realized at some point that having pointers to data wasn't extremely useful without dynamic allocation of some type, so I wrote something like:

在我熟悉之后,我接下来记得对动态分配感到困惑。我在某个时候意识到如果没有某种类型的动态分配,指向数据的指针并不是非常有用,所以我写了一些类似的东西:

char * x = NULL;
if (y) {
     char z[100];
     x = z;
}

to try to dynamically allocate some space. It didn't work. I wasn't sure that it would work, but I didn't know how else it might work.

尝试动态分配一些空间。它没有用。我不确定它会起作用,但我不知道它还能如何起作用。

I later learned about mallocand new, but they really seemed like magical memory generators to me. I knew nothing about how they might work.

后来我了解了mallocand new,但对我来说它们真的像是神奇的记忆生成器。我对它们的工作原理一无所知。

Some time later I was being taught recursion again (I'd learned it on my own before, but was in class now) and I asked how it worked under the hood -- where were the separate variables stored. My professor said "on the stack" and lots of things became clear to me. I had heard the term before and had implemented software stacks before. I had heard others refer to "the stack" long before, but had forgotten about it.

一段时间后,我再次被教授递归(我以前自己学过,但现在在课堂上),我问它在后台是如何工作的——单独的变量存储在哪里。我的教授说“在堆栈上”,很多事情对我来说变得很清楚。我以前听说过这个词,也曾经实现过软件栈。我很久以前就听说过其他人提到“堆栈”,但已经忘记了。

Around this time I also realized that using multidimensional arrays in C can get very confusing. I knew how they worked, but they were just so easy to get tangled up in that I decided to try to work around using them whenever I could. I think that the issue here was mostly syntactic (especially passing to or returning them from functions).

大约在这个时候,我也意识到在 C 中使用多维数组会变得非常混乱。我知道它们是如何工作的,但是它们很容易被纠缠在一起,所以我决定尽可能地尝试使用它们。我认为这里的问题主要是语法上的(尤其是传递给函数或从函数返回它们)。

Since I was writing C++ for school for the next year or two I got a lot of experience using pointers for data structures. Here I had a new set of troubles -- mixing up pointers. I would have multiple levels of pointers (things like node ***ptr;) trip me up. I'd dereference a pointer the wrong number of times and eventually resort to figuring out how many *I needed by trial and error.

因为我在接下来的一两年里为学校编写 C++,所以我在使用数据结构的指针方面获得了很多经验。在这里,我遇到了一组新的麻烦——混淆了指针。我会有多个级别的指针(例如node ***ptr;)绊倒我。我会以错误的次数取消引用一个指针,并最终*通过反复试验来确定我需要多少次。

At some point I learned how a program's heap worked (sort of, but good enough that it no longer kept me up at night). I remember reading that if you look a few bytes before the pointer that mallocon a certain system returns, you can see how much data was actually allocated. I realized that the code in malloccould ask for more memory from the OS and this memory was not part of my executable files. Having a decent working idea of how mallocworks is a really useful.

在某些时候,我了解了一个程序的堆是如何工作的(有点,但足够好以至于它不再让我彻夜难眠)。我记得读过,如果您malloc在某个系统上返回的指针之前查看几个字节,您可以看到实际分配了多少数据。我意识到中的代码malloc可能会要求操作系统提供更多内存,而这些内存不是我的可执行文件的一部分。对如何malloc工作有一个体面的工作理念是非常有用的。

Soon after this I took an assembly class, which didn't teach me as much about pointers as most programmers probably think. It did get me to think more about what assembly my code might be translated into. I had always tried to write efficient code, but now I had a better idea how to.

不久之后,我参加了一个汇编课程,该课程并没有像大多数程序员可能认为的那样教我太多关于指针的知识。它确实让我更多地思考我的代码可能被翻译成什么程序集。我一直试图编写高效的代码,但现在我有了更好的想法。

I also took a couple of classes where I had to write some lisp. When writing lisp I wasn't as concerned with efficiency as I was in C. I had very little idea what this code might be translated into if compiled, but I did know that it seemed like using lots of local named symbols (variables) made things a lot easier. At some point I wrote some AVL tree rotation code in a little bit of lisp, that I had a very hard time writing in C++ because of pointer issues. I realized that my aversion to what I thought were excess local variables had hindered my ability to write that and several other programs in C++.

我还参加了一些必须编写lisp的课程。在编写 lisp 时,我不像在 C 中那样关心效率。我几乎不知道如果编译这段代码会被翻译成什么,但我确实知道它似乎使用了许多本地命名符号(变量)事情轻松了很多。在某些时候,我用一点点 lisp 编写了一些 AVL 树旋转代码,由于指针问题,我很难用 C++ 编写。我意识到我对我认为过多的局部变量的厌恶阻碍了我用 C++ 编写它和其他几个程序的能力。

I also took a compilers class. While in this class I flipped ahead to the advanced material and learned about staticsingleassignment(SSA) and dead variables, which isn't that important except that it taught me that any decent compiler will do a decent job of dealing with variables which are no longer used. I already knew that more variables (including pointers) with correct types and good names would help me keep things straight in my head, but now I also knew that avoiding them for efficiency reasons was even more stupid than my less micro-optimization minded professors told me.

我还参加了编译器课程。在这门课上,我翻到了高级材料,学习了静态赋值(SSA) 和死变量,这并不重要,只是它告诉我,任何像样的编译器都可以很好地处理变量不再使用。我已经知道更多具有正确类型和好名字的变量(包括指针)将帮助我保持头脑清醒,但现在我也知道出于效率原因避免它们甚至比我不太关注微优化的教授所说的更愚蠢我。

So for me, knowing a good bit about the memory layout of a program helped a lot. Thinking about what my code means, both symbolically and on the hardware, helps me out. Using local pointers that have the correct type helps a lot. I often write code that looks like:

所以对我来说,了解一个程序的内存布局有很大帮助。考虑我的代码的象征意义和硬件意义,这对我有帮助。使用具有正确类型的本地指针有很大帮助。我经常写这样的代码:

int foo(struct frog * f, int x, int y) {
    struct leg * g = f->left_leg;
    struct toe * t = g->big_toe;
    process(t);

so that if I screw up a pointer type it is very clear by the compiler error what the problem is. If I did:

这样如果我搞砸了一个指针类型,编译器错误就会很清楚问题是什么。如果我这样做:

int foo(struct frog * f, int x, int y) {
    process(f->left_leg->big_toe);

and got any pointer type wrong in there, the compiler error would be a whole lot more difficult to figure out. I would be tempted to resort to trial and error changes in my frustration, and probably make things worse.

并且在那里得到任何指针类型错误,编译器错误将更难以弄清楚。我很想在沮丧中诉诸尝试和错误的改变,这可能会使事情变得更糟。