0

In C are there any times other than for arrays that the address-of operator is not needed? For example, I know this code needs the address of operator:

typedef struct foo_t {
    int bar;
} foo_t;

void foo_init(foo_t *f) { f->bar = 123; }

... {
    foo_t f;

    foo_init(&f);
}

But this code will not need the address-of operator:

... {
    char buffer[1024];
    memset(buffer, 0, 1024);
}

Here memset is declared as:

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

And in C it will auto cast that char[] to a void* - but trying to do the same for the foo_t like this:

 foo_t f;
 memset(f, 0, sizeof(foo_t));

Won't work and will generate the expected compile-time type error. Like with the char[] example if we use an array it will work:

foo_t list[16];
memset(foo, 0, sizeof(list));

It will again automatically cast the foo_t[] into a void*

Is this the only time this kind of cast will happen in C? How can I know when these casts will happen?

Kristopher Ives
  • 5,838
  • 7
  • 42
  • 67

3 Answers3

2

The only “other” (see comments) case of implicit address taking I know is with function pointers [1, 2]. Given a function

int
f(void);

the following two lines have identical meaning.

int (*fptr1)(void) = f;
int (*fptr2)(void) = &f;

Both make fptr1 and fptr2 a function pointer to f respectively.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
  • 2
    I would say this is *the only case*. With arrays it's not true that you "don't need" the `&` operator. Rather, use or non-use of the `&` operator give seriously different results. `arrayname` by itself is equivalent to `&arrayname[0]`, not `&arrayname`. – R.. GitHub STOP HELPING ICE Jan 19 '15 at 02:22
  • @R.. Indeed. That's also why I have used the weasel wording “implicit address taking” instead of “decay” because it is not the same that is going on here. I have also put the “other” in quotes now. – 5gon12eder Jan 19 '15 at 02:27
1

In this expression

char buffer[1024];
memset(buffer, 0, 1024);

the array decays to a pointer when passed to memset, memset expects a pointer to writable memory in it's first parameter.

This function

void foo_init(foo_t *f) 
{ 
    f->bar = 123; 
}

could also be written as

void foo_init(foo_t f) 
{ 
    f.bar = 123; 
}

but the passed parameter would be a copy of the original one and the changes would apply to the local copy only.

In the pointer version, the parameter points to the place where the struct is stored in memory and hence the changes are performed directly on to the same data that the pointer points to.

So you don't need to take the address of an array, because it's automaticaly decayed to a pointer that points to it's first element, when used as such, whereas when you pass an object allocated on the stack and you want to change it in the reciever function, you need to pass a pointer to it, for which you use the address of operator.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • Thanks @iharob, I think I understand that in the question. My concern is when is this implicit casting going to happen in C otherwise. I'm mainly looking for where in the C spec (of any fashion) that it outlines this behavior so I can understand what else it may apply to. – Kristopher Ives Jan 19 '15 at 02:02
1

String literals are assigned by address to pointers, and by "value" when used as the rhs of an initialization:

const char *str_ptr = "foo";  /* str_ptr points to a string "foo",
                                 in read-only memory. */

char chr_ar[] = "barbar";     /* chr_ar is 7 bytes, and is initialized
                                 with the bytes "barbar" */
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328