最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Why does K&R say that pointers are preferable to arrays as function parameters? - Stack Overflow

programmeradmin2浏览0评论

From K&R page 99:

" we prefer the latter because it says more explicitly that the variable is a pointer."

I need some clarification as to why "saying more explicitly that the variable is a pointer" would have any importance? I would expect the reason is for the program to be faster rather than more explicit, as stated in page 97:

"The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand"

But in that case, why would the pointer version be faster? if arr[i] just equivalent to *(a+i) why would the program be faster? is it because C doesn't need to convert the array to the pointer version?

From K&R page 99:

" we prefer the latter because it says more explicitly that the variable is a pointer."

I need some clarification as to why "saying more explicitly that the variable is a pointer" would have any importance? I would expect the reason is for the program to be faster rather than more explicit, as stated in page 97:

"The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand"

But in that case, why would the pointer version be faster? if arr[i] just equivalent to *(a+i) why would the program be faster? is it because C doesn't need to convert the array to the pointer version?

Share Improve this question edited 1 hour ago cigien 60.5k11 gold badges81 silver badges121 bronze badges asked 20 hours ago Roee ZamirRoee Zamir 1458 bronze badges 15
  • 2 It clearly states that these are equivalent, that is in both cases s is a pointer, and has absolutely no difference in terms of performance or anything else. It is just the star notation makes it clearer to the reader. In this case these are just two different notations of the same thing. Make no mistake though. arrays are not pointers in a general context, it is just they decay to pointers when used as function parameters. – Eugene Sh. Commented 20 hours ago
  • 5 I think the quote on p.97 is simply wrong, unless there's some context you've left out. There should be no difference in performance when we're talking about a function parameter. – Barmar Commented 19 hours ago
  • 1 Many beginners think that they can use sizeof s to get the size of the array that was passed to the function. But since it's actually a pointer, this is just the size of a pointer. This is an example of it being unclear. – Barmar Commented 19 hours ago
  • 2 The "faster" comment is indeed at the bottom of page 97 of K&R2, and not present in K&R1 (at least to my quick perusal). My guess is that the compiler Kernigan and Ritchie were using at the time generated more efficient code with the pointer format. Modern compilers should generate the same code (because, as the first quote says, the forms are equivalent) – One Guy Hacking Commented 19 hours ago
  • 2 One quirk is that char *s = "sam"; . . . is not equivalent to char s[] = "sam"; The later can be modified, the 1st cannot -- not without a segfault. That's my experi3nce anyway, maybe someone from the S/O community will tell why -- or perhaps tell why I am wrong. Either is welcome by me -- always illuminating one way or another. – greg spears Commented 19 hours ago
 |  Show 10 more comments

4 Answers 4

Reset to default 10

Outside of parameter list, char s[] and char *s are different.

void foo( void ) {
   char a[] = "abcdef";  // An array of 7 `char` elements.
   char *p = "abcdef";   // A pointer that points to a sequence of 7 `char` objects.
}

In a parameter list, char s[] and char *s are 100% equivalent by definition.

void foo(
   char p1[],  // A pointer that points to a `char` object.
   char *p2    // A pointer that points to a `char` object.
) {
}

It's saying that since s is a pointer, it's clearer to use char *s. Using char s[], while equivalent, could mislead "the uninitiated" into thinking it's an array when it's not.

Note that not everyone agrees with always using char *s instead of char s[] for parameters. I'm just explaining the opinion expressed by the book as requested.


Since char s[] and char *s are equivalent in a parameter list, there is no difference in performance. I suspect the passage you quoted about performance is taken from a different context, one where char s[] and char *s are not found in a parameter list.

char *s = "abcdef"; will likely be faster than char s[] = "abcdef"; because the former is commonly implemented as simply loading a pointer to an existing string in the binary image, while the latter is commonly implemented as copying 7 byte to the stack.

But this doesn't apply for parameters. They are 100% equivalent there.

Here's a little more context for the quote about the pointer version being faster:

Any operation that can be achieved by array subscripting can also be done with pointers. The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand.

And, a pages later:

There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable.... But an array name is not a variable.

[My page numbers don't match, so we must be reading different editions.]

If you have an array name, and you want to dereference to a particular offset, you first have to (1) load the array address into a register and (2) do the arithmetic to get to the offset. If you have already have a pointer to the first element, then you've effectively already done the first step.

This doesn't matter for one-off accesses, but it might have mattered for an algorithm that makes repeated accesses, either sequentially or jumping around.

But the details are specific to the hardware and the compiler, both of which have evolved a lot since they wrote it. Over the years, I've seen demonstrations comparing an array-indexing and a pointer-dereferencing versions of the same algorithm. Sometimes the faster one was indexed, sometimes it was by pointer. As the years went by, the difference was generally less and less significant.

Both methods are valid, and nowadays there usually isn't a performance difference. It's important to understand both. But when deciding which to use, use the one that best expresses the algorithm. K&R's preference for the pointer notation is an attempt to remind the reader that pointer decay happens, and you can get confused if you pretend it doesn't.

Spend some time pondering the equivalence of two oft-seen versions of a function declaration:

    int main( int argc, char **argv ) {
    //
    int main( int argc, char *argv[] ) {

By "equivalance", for both versions argv is, in isolation, a variable containing a memory address to be interpreted as a pointer.

In the first version, the reader understands argv to be a "pointer to a pointer to a char", but has learned that the char storage is the first byte of a C-string, and that the next pointer accessible with ++argv will (usually) point to the next C-string, and so on.

The first is compact notation, and the function likely advances the pointer argv as it deals with each command line parameter sequentially.

    ...
    for( --argc; argc; argc-- ) { // clumsy, but worth pondering to learn
        char *param = *(++argv);
        ...

In the second version, the dereferencing of argv is, perhaps, somewhat more explicit about there being an array (of argc elements that are themselves pointers) to be found down that path.

The second hints that, instead of simply advancing the pointer argv, there may be an expectation that the position of each command line parameter is significant.
Eg: myrename foo bar knows that the file to be renamed will always be at argv[1]

    ...
    // Not shown: code that ensures there are two-and-only-two parameters.
    // It's up to the function (and caller) to not access outside of claimed memory.
    char *exeName = argv[0]; // name of this executable
    char *curName = argv[1];
    char *newName = argv[2];
    ...

As is often the case, there are many ways to skin a cat.
Because of this equivalence, the coder can choose whichever syntax provides the greatest clarity in the code. Eventually, you will come to see the syntaxes as interchangeable, and the choice of which to use having little consequence (when no other problems are present.)

Mastering pointers is one of the few hurdles to using C (or its cousins), but is a worthwhile requirement to becoming a good coder.

i need some clarification as to why "saying more explicitly that the variable is a pointer" would have any importance?

Understanding how arrays whenever used in expressions or written as function parameters get adjusted ("decay") into a pointer to the first element is one of the classic things that everyone learning C is struggling with. Therefore the array version might be confusing, example:

void func (int array[10]);

Some might incorrectly think that this creates a copy of the array passed by showing 10 integers onto the stack. But it gets adjusted to a pointer of the first element of the passed array, and so it is equivalent to int* array.


The full quote and context of K&R 2nd edition:

Any operation that can be achieved by array subscripting can also be done with pointers. The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand.

First of all, array subscripting always involves array decay so it can't be used with arrays, it is always used with (decayed) pointers.

"The pointer version will in general be faster" is simply utter nonsense. There's no way even for the most dogmatic K&R fanboy to brush this blatantly incorrect statement under the carpet and save face of the authors.

Get a better book, preferably from this millennium.

发布评论

评论列表(0)

  1. 暂无评论