Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does * need to be put before (&a) to subtract a (a is an array)?

Tags:

c++

pointers

I was learning how to find the length of an array and I'm baffled by this solution. I tried to find an explanation online but there seems to be none.

int arr[5] = {5, 8, 1, 3, 6};
   int len = *(&arr + 1) - arr;
   cout << "The length of the array is: " << len;
like image 446
Dat Le Avatar asked Aug 16 '20 23:08

Dat Le


People also ask

Why * is used in regex?

* - means "0 or more instances of the preceding regex token"

Is a comma needed before before?

Before is the subordinator, here connecting a participle phrase. If the phrase were first, it would require the comma. Before letting a smirk grace her face, she shakes her head aggressively. This goes for all subordinating conjunctions, except that there are some descriptive rules for some.

What is the meaning of +$ in regex?

The usual context of wildcard characters is in globbing similar names in a list of files, whereas regexes are usually employed in applications that pattern-match text strings in general. For example, the regex ^[ \t]+|[ \t]+$ matches excess whitespace at the beginning or end of a line.

How do you handle special characters in regex?

Escape Sequences (\char): To match a character having special meaning in regex, you need to use a escape sequence prefix with a backslash ( \ ). E.g., \. matches "." ; regex \+ matches "+" ; and regex \( matches "(" .

When do you use ‘a’ and ‘an’ before words?

There is only one exception to the rule that ‘a’ is used before words beginning with a vowel sound and ‘an’ before words beginning with a consonant sound: in British English, ‘an’ is sometimes used before words beginnning with an h followed by an unstressed vowel.

Why do we sometimes use'a'and'an'before'u'?

We always us an before the vowels a, e, i, and o, but with u we sometimes use a and sometimes an. This is because the initial u sometimes has a short vowel sound and sometimes it has a long vowel sound: an umbrella, an upset election, but a unicorn, a uniform, a university.

Why do we use./in front of the shell script?

By requiring ./ to be used in front, the shell knows that you want to execute the application with the given name and not a built-in command with that name. Show activity on this post. ./ executes files that are not in your $PATH, rather it executes the file in the current directory (or another via ./home/stefano/script.sh ).

Do we say ‘an’ before every word that begins with a vowel?

Indeed, we say ‘an’ before every word that begins with a vowel sound, however it may be spelled: we say ‘an hour’ or ‘an honor’, because the h is silent in those words, which are pronounced as if they were spelled ‘an ower’ and ‘an onner’, though of course we say ‘a hot day’, ‘a house’, ‘a horror’, since in those words the initial h is pronounced.


Video Answer


3 Answers

The memory address of the array is the same as the memory address of the first element, and when you add to or subtract from a pointer, it is done by the size of the type it points to, so:

  • arr refers to int, and &arr refers to int[5].
  • &arr+1 increments the memory address in the size of five integers.
  • If you do (&arr+1)-arr you get a compile error, because they are different types.
  • If you do (&arr+1)-&arr you get 1, because the offset of the memory address is the same as one size of int[5].
  • Therefore, when you do *(&arr+1), you get the same memory address but pointing to int and not int[5]. Now you wont get a compile error, because both pointers point to int and you get the offset of the memory address in terms of int size, and not int[5]. Memory addresses and types are quite difficult to explain sometimes, I hope I made it clear. Here you have some code you can run to see some of the concepts mentioned:
   int arr[5] = {5, 8, 1, 3, 6};
   int len = *(&arr + 1) - arr;
   
   cout << "arr: " << arr << endl;
   cout << "arr + 1: " << arr+1 << endl;
   cout << "&arr: " << &arr << endl;
   cout << "&arr + 1: " << &arr+1 << endl;
   cout << "*(&arr + 1): " << *(&arr+1) << endl;
   
   // cout << "&arr + 1 - arr: " << &arr+1-arr << endl;
   // error: invalid operands of types ‘int (*)[5]’ and ‘int [5]’ to binary ‘operator-’

   cout << "The length of the array is: " << len;
like image 168
Miguel Avatar answered Oct 16 '22 06:10

Miguel


The type of the array arr is int[5], the type of &arr is int(*)[5]. (&arr + 1) increases the array address on sizeof(int[5]) as it's done by the rules of the pointer arithmetic, i.e. computes the address after the array. *(&arr + 1) is int[5], an array right after arr, where arr[5] would place. The both arguments of the substractions decay to int*. The substraction of pointers to int gives 5.

This may be considered as undefined behavior, since substraction of pointers belonging to different object storages is not defined. Also results of expressions with pointers addressing unallocated memory (like the (&arr + 1)) are undefined.

like image 25
273K Avatar answered Oct 16 '22 07:10

273K


First, the traditional way to get the size of an array is sizeof a/sizeof *a. C++11 adds std::extent<decltype(a)>::value. There is of course no way to get an array’s size from just a pointer to it, as in

void f(int x[]) {/* no size here */}

Since an array is not a suitable operand to -, the array-to-pointer conversion occurs for the right-hand operand, producing an int*. Both operands must be of this type for the subtraction to result in a number of ints. &arr is of course a pointer to the array (of type int(*)[5], which conveys the size), and so therefore is &arr+1. Adding a * (or, equivalently, writing (&arr)[1]) produces an lvalue that supposedly refers to “the next array after arr”, which itself decays to a pointer that works with -.

However, as the indexing form indicates, this involves referring to an array that does not exist and is thus undefined behavior.

like image 40
Davis Herring Avatar answered Oct 16 '22 08:10

Davis Herring