0

I wonder about if there is a reason to use an array, consisted of one element object, instead of just to use one object.

Like, f.e.

int a[1] = {10};

instead of just

int a = 10;

Of course, there is a big difference in the context of accessing the value of 10 in the later code between both cases, by the use of a:

  1. When a is declared as an array, like
int a[1] = {10};

a decays to a pointer to the first element object of the array of a, thus a evaluates to type int*, when a is used later in the program.

  1. When a is declared as an identifier for a certain object, like
int a = 10;

a is of type int.

If we would want to pass the value of 10 to a function, we have to take attention on that and must distinguish between both uses.

But that does not answer my question for why I use the one way instead of the other one.


  • Are there any places in C and/or C++, where an array is needed instead of just one object?
  • Is there are physical difference in the size of the allocation in memory?
  • Do C and C++ differ in this context?
  • Is there a reason for choosing an array of one element instead of one object?

Reason for tagging with C and C++: I tagged it with both language tags because both statements are valid in C and C++, and at the actual moment, I don´t know of any difference between both languages in that case. If there is a difference, please mind it.

Thanks for your help.

  • 5
    Important note: Arrays are *not* pointers! An array can *decay* to a pointer to its first element, but they are not pointers themselves. For an array such as `int a[1];` the type of `a` is `int[1]`. – Some programmer dude Jan 18 '20 at 10:50
  • @Someprogrammerdude I know, but it is good to mind that. I shall point this out more specifically. – RobertS supports Monica Cellio Jan 18 '20 at 10:53
  • As for why someone would use an array of one element rather than a single non-array object, it could be that they might find it easier to work with just because of the array decay to pointer, rather than having to use the address-of operator `&`? – Some programmer dude Jan 18 '20 at 10:54
  • 1
    *Why do I use an array of one element instead of just one object?* I don't know. Why do you? Is this common? Where have you seen it? I feel like your question fails to explain why you think this is something that "people do" in the first place. – super Jan 18 '20 at 10:55
  • @ikegami I have edited it already. Thanks. – RobertS supports Monica Cellio Jan 18 '20 at 10:55
  • You only partially fixed it. The type of `a` is `int[1]`, not `int*`. It *decays* into `int*` if coerced; it's not a `int*`. For example, `sizeof(a)` and `sizeof(int*)` can be different. Suggested wording: *Thus `a` can be used where an `int*` is expected.* – ikegami Jan 18 '20 at 10:55
  • There is no real difference, only semantics. And if you use `int a[1];` people that real your code will find it weird and confusing. So there is absolutely no good reason to use `int a[1];` instead of `int a;`. – ALX23z Jan 18 '20 at 10:57
  • @ikegami Is it better now? – RobertS supports Monica Cellio Jan 18 '20 at 10:58
  • Re "*If we would want to pass the value of 10 to a function, we have to take attention on that and must distinguish between both uses.*", You have to do that either way. With `int x`: `takes_pointer(&x)` or `takes_int(x)`; with `int x[1]`: `takes_pointer(x)` or `takes_int(x[0])`. Having to use `x[0]` all over the place to avoid a `&` is really weird to me. – ikegami Jan 18 '20 at 11:02
  • @super I´d wanted to name it "*Why should I use an array of one element instead of just one object?*" originally, but since "should" questions are deprecated, I choosed this wording. – RobertS supports Monica Cellio Jan 18 '20 at 11:03
  • 1
    @RobertS-ReinstateMonica I think my confusion is more about why are you asking this question at all? Your question kind of implies that this is something that is actually done and you wonder why. As far as I know this has never been a thing. – super Jan 18 '20 at 11:05
  • @super To ask if there is a specific reason in certain cases to chose one for the other. What would be your suggestion to rename the question title? – RobertS supports Monica Cellio Jan 18 '20 at 11:08
  • When using this analogy, "*I did not eat onions only my whole life*". I did not implied, that I do use this technique. My question is about: "*Why should I eat onions at all?*" The wording might be wrong, but the question has its well-decided reason to be. – RobertS supports Monica Cellio Jan 18 '20 at 11:19
  • @RobertS-ReinstateMonica No, your missing the point. Sure, the analogy could be a lot better. BUT there is nothing in your question that explains where the question is coming from. Have you talked to people who said this was a good idea? Have you seen it used in code? The reason why this topic is relevant is missing. – super Jan 18 '20 at 11:22
  • @super I did not seen this technique anywhere and did not heard from coders who do it like that. But just because I did not encountered this technique (already), does not mean there is no reason to distinguish and it is not reasonable to ask for it here, if it has a reason. I asked this question for exactly the reason to get an answer to it, if it is beneficial or not to choose one way for the other. My wording maybe had made the confusion, that this technique would be used, but there is no duty to justify a question. Just answer or comment, that it is not getting used and everything is fine. – RobertS supports Monica Cellio Jan 18 '20 at 11:44
  • Occasionally it is convenient to use a compound literal to create an array of one element when testing a function that takes a pointer, e.g. `func((int[]){ 5 });`. – ad absurdum Jan 18 '20 at 13:27

6 Answers6

2

In my opinion there is no point in declaring an array for one object. I would strongly recommend to use the basic: a = 10 ;

1

Are there any places in C and/or C++, where an array is needed instead of just one object?

I think you mostly will encounter a C-style array with one object as the end-case of a recursive function on one object. If you have a function that takes an array in a C-like manner (f(int* array, int length)) you could use this to apply the function to only one input without providing another overload. But you could do the same with int a = 42; f(&a, 1);.

Is there are physical difference in the size of the allocation in memory?

No. int a[1] = {42} and int a = 42 do exactly the same to the stack.

Do C and C++ differ in this context?

No.

Why do I use an array of one element instead of just one object?

An array with compile-time size of 1 (like you did above) is probably used very little. There is a difference between

int a[1] = {42};
// and
int b = 42;
int *a = &b;

since an array is not a pointer but only decays to one. But the difference in using them is very minor. The most notable difference in using them (thx @Scheff) should be that you can use std::begin(a) and std::end(a) on int a[1] but not on int *a. This is only a difference in C++. Note that this disappears once the array has decayed to a pointer. Then you substitute them by a and a+1 respectively.

I could imagine, that one do int a[1] = {42};, if one wants to initialize an object on the stack and directly have a pointer to it (and not really use the value itself), since it is a bit shorter. But I have never seen that myself and I would actually consider it bad style. I would think that it would be very uncommon in C++ code, since raw-pointers themselves are not that common.

I have actually more often seen an array of length 0, see for usage here. Since those seem to be technically illegal in older versions of C are invalid in C (thx for the comments), one could use an array of length 1 to be legal. But to the best of my knowledge, most compilers implemented 0 length arrays since pretty much forever, so most people would probably ignore that and use a 0 length array.

n314159
  • 4,990
  • 1
  • 5
  • 20
  • Arrays of length zero are still disallowed by the standards, definitively in C++ and I think also in C. But as you say compilers usually support it as extension. – walnut Jan 18 '20 at 11:45
  • An array of length zero is still invalid in C. – Lxer Lx Jan 18 '20 at 12:02
  • The array might be a placeholder for something which has currently 1 element but might get more in the future. For an array, container templates like e.g. `std::begin()` and `std::end()` can be used. For a single object variable, I'm not that sure although with some pointer trickery the same can be achieved probably. – Scheff's Cat Jan 18 '20 at 13:17
  • @Scheff For dynamic sized arrays you must use pointers and `new`/`malloc` (in C++ you should actually use `std::vector`). You cannot increase the size of a `int[1]` later. You are correct that you can use `begin` and `end` on an `int[N]` and not on a `int*` that points to an array. I will add that. – n314159 Jan 18 '20 at 14:41
  • I didn't mean dynamic arrays. Sometimes (e.g. for configuration), you might establish an array in source code. Later (over evolving development) there can be easily added elements without breaking the rest of code. Of course, I would prefer `int a[] = { 42 };` i.e. let compiler count the current number of elements in initializer. – Scheff's Cat Jan 18 '20 at 15:29
1

Are there any places in C and/or C++, where an array is needed instead of just one object?

Why do I use an array of one element instead of just one object?

There are many functions that can work on arrays, that take a pointer argument. However, as machine_1 already pointed out, you can easily get the pointer to a regular object and pass that to a function.

There are a few cases where it does make a difference though. In C++, if you would want to use range-for to iterate over a number of objects, you can write:

int a[1] = {42};
for (auto &value: a)
     ...

But you can't write:

int a = 42;
for (auto &value: a)
     ...

The above example looks silly on its own, but it becomes a real problem when you define generic functions using templates. So sometimes you'd want to store a value in an array of length 1 just to make it easier to use those functions.

In C99 and later, but not in C++, you can also use flexible array members. Such members work like arrays, but they take up no space, as if they have zero length. Consider having a network packet with a header and a variable amount of data. A struct that represents a packet could look like:

struct packet {
    address_t source;
    address_t destination;
    size_t length;
    char data[]; // flexible array member
};

One would allocate memory for such a struct like so:

size_t data_length;
...
struct packet *pkt = malloc(sizeof(*pkt) + data_length);

And then one can read and write to the data portion like so:

for (size_t i = 0; i < data_length; i++)
     pkt->data[i] = ...;

You don't need the data[] array here, since you could also access the data by doing something like ((char *)pkt + sizeof(*pkt))[i], using an array member at the end of the struct allows writing much more compact, readable and safe code.

It is possible to do a similar trick in C++ by using an array of length 1.

Is there are physical difference in the size of the allocation in memory?

No.

Do C and C++ differ in this context?

No.

Community
  • 1
  • 1
G. Sliepen
  • 7,637
  • 1
  • 15
  • 31
  • 2
    You might want to make it clearer that only C supports flexible array members and that C++ doesn't. I think even in C the array must have empty bounds, not zero or one, for this to be well-defined. – walnut Jan 18 '20 at 11:33
  • This is simply wrong: ... _or even zero, in C99 or later_ ... **An array cannot have zero size in C.** – Lxer Lx Jan 18 '20 at 12:10
  • @LxerLx: You are right that you can't say `int a[0]` in any standard C, and `sizeof()` on a flexible array member is not allowed. However, flexible array members do have effectively zero size. I updated the text, I hope it is more correct now, if it is still incorrect please suggest how to improve it. – G. Sliepen Jan 18 '20 at 13:02
1

Sometimes a function written for the common case will mean taking an array, for example in C you might have something like :

#define CULL_OBJECTS(objs) {\ 
           for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)\ 
           {\ 
                ++culled_objects;\ 
                cull_subobjects(objs[i]);\ 
           }\

or in C++ :

template<typename T>
void CullObjects(T& objs)
{
    for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)
    {
        ++culled_objects;
        cull_subobjects(objs[i]);
    }
}

Which could either be called by passing Obj objArr[1000] or Obj obj[1].

George
  • 2,101
  • 1
  • 13
  • 27
0

You should not declare an array consisting of one object. If you need a single variable, then declare it as such. But to answer your question, one would want to write something like:

int a[1];

probably for convenience when working with functions that take a pointer as an argument. Take for example the function memset() declared as:

void * memset (void *ptr, int value, size_t num );

If you declare a single variable and want to use memset() on it, the you must call it as:

int a;
memset(&a, val, sizeof(int));

whilst if you declare a as int a[1], then you'd call it as:

memset(a, val, sizeof(int));

However, the former use is for doing something either weird or unusual!

machine_1
  • 4,266
  • 2
  • 21
  • 42
0

There is no reason to use int a[1]; instead of int a;. Use &a to pass the pointer to it when needed. Other people will be very confused with int a[1]; if you ever write it - it will look like a bug.

Then you probably ask why would it be even needed in the language?

This is simple. Say you want a fixed array of size N, e.g., int a[N]; and you don't know the value of N. This is either a macro, result of a constexpr computation, or parameter of a template. Thus int a[1] needs to be supported for it to work.

ALX23z
  • 4,456
  • 1
  • 11
  • 18