9

Arrays and pointers are not the same thing in C, although they are related and can be used similarly. So far we all agree.

However, I don't see why arrays were included in C, when pointers could have done their job perfectly.

I am not saying to remove the array notation (e.g, a[5] or int a[4] = {0,1,2,3};), which is quite useful and convenient. But you could have that same notation working on top of pointers (as is the case), as a cosmetic measure. So the array notation is not a reason to have arrays, just the notation!

The only difference I see is that arrays are constant pointers, and the size of memory they point to can't be changed. But this can be achieved with pointers as well, exactly by making them constant (the memory wouldn't be of fixed size, but I am not sure if this is an issue).

So why not have only pointers and let the programmer decide how the pointer should behave (i.e., constant, not constant, fixed size, variable size, etc)?

7
  • 7
    Why have char when you can achieve the same thing with byte?
    – WuHoUnited
    Oct 20, 2011 at 23:43
  • 2
    On a more serious note though, how do you intend to accomplish the memory allocation with a pointer?
    – WuHoUnited
    Oct 20, 2011 at 23:46
  • 5
    Personally, I think of pointers as (sometimes) pretending to be arrays rather than visa versa. In many other languages, pointers don't have array-like behaviour - if you want to access an array through a pointer you either use a pointer-to-array type or you do pointer arithmetic (counting in bytes, not elements). I'd bet a fair amount of money that the inventors of C thought in terms of tweaking pointers to get more convenient array-like behaviour - I very much doubt they already had array-like pointer behaviour then decided "I know, lets add arrays too".
    – user8709
    Oct 20, 2011 at 23:50
  • 4
    Why have 0xAB when you can achieve the same thing with 171?
    – e-MEE
    Oct 21, 2011 at 5:23
  • 3
    why having compound expressions like x = a + b * 2; when you could achieve the same with a sequence of simple expressions like x = b; x*=2; x+=a;?
    – fortran
    Oct 21, 2011 at 14:01

6 Answers 6

14

Arrays are contiguous memory created on the stack. You can't guarantee contiguous stack memory without this syntactic sugar, and even if you could, you'd have to allocate a separate pointer in order to be able to do the pointer arithmetic (unless you wanted to do *(&foo + x), which I'm not sure but it might violate l-value semantics, but is at least quite awkward, and would scream out for some kind of syntactic sugar). Design-wise, it also is a form of encapsulation, since you can refer to the collection with a single identifier (which would otherwise require a separate pointer). And even if you could allocate them contiguously and allocated a separate pointer to reference them, you'd have either int fooForSomething, fooForSomethingElse... which forces a fair amount of creativity as your collection grows, so you might think to simplify with int foo1, foo2 ..., which looks just like an array but is harder to maintain.

6
  • Oh, and pass by value for foo1, foo2... gets messy quickly, especially if you want to allow a variable number of members.
    – kylben
    Oct 21, 2011 at 0:19
  • 2
    Only arrays declared as automatics end up on the stack. Anything else (i.e., statics) usually ends up elsewhere depending on on the environment.
    – Blrfl
    Oct 21, 2011 at 10:48
  • It is not a "syntactic sugar", it is much deeper - an important part of the C type system, as well as the infamous array decay.
    – SK-logic
    Oct 21, 2011 at 10:52
  • 1
    what is the difference between an array on the stack and alloca()
    – sylvanaar
    Oct 21, 2011 at 11:33
  • @sylvanaar, see this SO question: stackoverflow.com/questions/1018853/… I'd actually never heard of it before, but it is apparently non-standard and dangerous in the ways I would expect such a thing to be dangerous.
    – kylben
    Oct 21, 2011 at 14:07
13

Array notation is convenient, easier to read, and less prone to errors. It provides a formalism over pointers. It might be syntactic sugar, but we all need a little sweetness once in awhile, don't we?

As with all abstractions, you give up a little flexibility for the convenience that the abstraction provides.

2
  • 1
    As I mention in the question, I am not against the array notation. But that same notation could work on top of pointers, so where's the need for arrays themselves? Oct 20, 2011 at 23:21
  • 1
    @DanielScocco - Maybe it could. But it was made like this, nevertheless. End of story. No one can really answer this, as no one knows what was going in the author's head at that time.
    – Rook
    Oct 21, 2011 at 0:05
10

I am surprised that nobody has commented anything about multidimensional arrays yet.

If you have a matrix made of "nested pointers" (say int **p) what you have in each "row" (outer dimension) is a pointer that points to the first element in that row, so accessing a value requires two memory access. Plus, the memory it requires is sizeof(*int)*n + n*m*sizeof(int).

In the bidimensional array scenario int p[n][m], accessing an element requires just one memory access, because the address of the row is calculated rather than looked up; and the memory required is just n*m*sizeof(int).

Another place where an array cannot be replaced by a pointer is inside structures.

struct s {
    int[2];
    float;
}

is definitively not the same as

struct s {
   *int;
   float;
}

the size of the array is important there, and pointers do not have that information.

So yes, unidimensional arrays and single pointers are mostly interchangeable, but their similarities end there.

7
  • Show us the difference in assembler. Multidimensional arrays, structure packing and padding they are all just ways to provide a frame of reference that makes sense to the humans who have to make sense of and use the language.
    – sylvanaar
    Oct 21, 2011 at 11:55
  • @sylvanaar are you serious? do you really need to see the assembler to be sure that first structure holds space for two integers and a float, and the second one just for storing a memory address and a float?
    – fortran
    Oct 21, 2011 at 11:59
  • 1
    I don't follow you. What has to do the instruction set with all of this? The op was asking what things you could do with arrays and not with pointers, and declaring a struct with a fixed size array cannot be emulated with pointers. About multidimensional arrays, of course you can have just a chunk of memory and calculate the index of cell i,j by i*cols+j, but I think not having to do it alone is a reason good enough to justify the existence of array types.
    – fortran
    Oct 21, 2011 at 13:50
  • 2
    "Declaring structs [...] does create static memory allocations in the compiled image" No, declaring a variable (of struct type, or any other type) does this. Declaring a struct just tells the compiler how big that type is and what offsets each of its members are; you might never allocate one, or only allocate them as local variables.
    – Random832
    Oct 21, 2011 at 15:40
  • 1
    +1 for cogently identifying the practical value of having arrays of a fixed size be a "type" as far as the compiler is concerned - multidimensional arrays, and in particular the fact that you can trivially index into them with the compiler doing the pointer arithmetic with the right size for you, fall out naturally and elegantly from the other simple language rules by making arrays a real "type" - you could achieve the same syntactic sugar without that, but the logic would have to be more special-case, both in the compiler and in the language specification.
    – mtraceur
    Oct 17, 2019 at 22:57
2

Why would I want to not be able to use arrays for value types?

int a[4] = {0,1,2,3};

7
  • You would still be able to use that even if we just had pointers, wouldn't you? The compiler would just have to know what to do. Oct 20, 2011 at 23:23
  • 2
    @DanielScocco and how would it know what to do? arrays Oct 20, 2011 at 23:41
  • Agreed - what would you call the feature that reserves space for a sequence of same-type items as a local or global variable, if not an array? A pointer type is a pointer type - it doesn't specify whether what it points to is a sequence, or what sized sequence.
    – user8709
    Oct 20, 2011 at 23:45
  • 4
    @DanielScocco What comes with an array that doesn't come with a pointer is information about the size. So a (pointer, size) pair or a (pointer, pointer) pair can indeed hold just as much information as the name of an array. Whether this means that arrays are pairs of pointers (or vice-versa) seems more like a metaphysical question, so I'm not really interested in answering that. (The answer is probably no as pairs of pointers look more like slices, and hence can do more than just refer to an array.)
    – Luc Danton
    Oct 21, 2011 at 0:40
  • 1
    @Daniel Scocco, arrays has a size. You can allocate an array on stack, you can put an array into a contiguous structure, you can use it within a union. If the array type did not exist, it would not be possible.
    – SK-logic
    Oct 21, 2011 at 10:51
1

How would you handle platforms, like the 8031 without external memory, that don't support malloc or alloca? Perhaps you're forgetting that C isn't just for big iron but is also for elevator controllers and toasters.

1

In C, array notation within expressions is always simply pointer arithmetic. All uses of an array identifier in an expression are immediately converted from "array of T" to "pointer to T" and the value is converted to a pointer to the first element of the array. Array notation (e.g. a[1][2]) is always expanded into pointer arithmetic (e.g. *(*(t+1)+2)).

However array notation in declarations and definitions is something else entirely. An array declarator describes an "array of T" type where the values of this type are sequences of elements of type T. A definition of an array object is all about using convenient and easily understood array notation to allocate the appropriate amount of storage for the desired array of objects such that the array identifier refers to this storage without it looking like a pointer. In effect array notation in a declaration or definition is a macro generating an expression using sizeof() and arithmetic, and in the case of a definition, the equivalent of alloca() for auto arrays or its equivalent in the linker for global arrays, and doing it all at compile time (well except for C99 variable-length arrays).

The use of array notation in expressions and the use of array types is not so tightly connected, though it is tradition and idiom to use array notation in expressions to reference storage in objects declared and/or defined as arrays. You can just as easily use array notation with a pointer type in order to make the pointer arithmetic cleaner and more meaningful. Indeed in C an expression of the form e1[e2] is precisely equivalent to the expression *((e1)+(e2)). The usual binary conversion are applied to the two operands, and the result is always an lvalue. Since the indirection operator (*) must have a pointer as its operand, one of e1 and e2 must be a pointer and the other must be an integer, but it does not matter which since the initial unary conversion for any "array of T" is to convert it to "pointer to T". Array notation in expressions is in effect a compiler (language-level) macro to generate pointer arithmetic expressions.

So really C already does work the way you suggest but you are confusing the use of the notation in two very separate contexts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.