0

I learned char array don't use & in scanf because char store point, not string itself.

char s1[10];
scanf("%s", s1);

But, why dynamic allocated int array use & in scanf although it use pointer?

int *arr = (int *)malloc(sizeof(int)*3);
scanf("%d", &arr[1]);
4rigener
  • 346
  • 3
  • 18
  • 1
    arr[1] is not a pointer, so you should add & before it – D023F Nov 28 '19 at 01:23
  • `scanf("%s", s1);` is equivalent to `scanf("%s", &s1[0]);` and `scanf("%d", &arr[1]);` is equivalent to `scanf("%d", arr + 1);`. – Pablo Nov 28 '19 at 01:24
  • `int arr[3] = (int *)malloc(sizeof(int)*3)` is not valid code anyway. The result of `malloc()`, whether cast or not, cannot be used to initialise an array. – Peter Nov 28 '19 at 04:27

3 Answers3

1

This is completely wrong:

int arr[3] = (int *)malloc(sizeof(int)*3);

because you are trying to allocate memory to an array which is not allowed.
It should be:

int * arr = malloc(sizeof(int)*3);

When you do this, the in-memory view would be something like this (assuming malloc is success):

    +-----------+
    |   |   |   |
    +-----------+
    ^
    |
   arr

arr is a pointer pointing to the base address of the memory.
arr[1] is the first element of array (a single element of integer array arr) and
&arr[1] is the address of first element of array arr.

    +-----------+
    |   |   |   |
    +-----------+
        ^
        |
       &arr[1]

When you take input in first element of array arr you have to pass the address of first element of array to scanf() which is &arr[1].

& used with scanf() arguments has nothing to do with dynamic allocation. If you want to take input in an element of fixed length array (size determined at compile time), the syntax will be same:

int arr[3];

scanf("%d", &arr[1]);

Please let me know if you have any further questions.

H.S.
  • 11,654
  • 2
  • 15
  • 32
  • A good alternative to `arr = malloc(sizeof(int)*3);` is `arr = malloc(sizeof *arr * 3);`. Easier to write correctly, review and maintain. – chux - Reinstate Monica Nov 28 '19 at 03:08
  • @chux: I prefer `malloc(3 * sizeof *arr)`. Then the operand of `sizeof` is a little easier to distinguish visually. Also, if you are doing a multidimensional array, `malloc(rows * columns * sizeof *p)` both matches the order the dimensions would be in an array definition and continues the sizes from biggest thing to smallest, with the size of a single object last. – Eric Postpischil Nov 28 '19 at 03:18
  • @EricPostpischil `rows * columns * sizeof *p` has a disadvantage over `sizeof *p * rows * columns` when `rows, columns` may be narrower than `size_t` - e.g. `int`. A product with `sizeof *p * rows * columns` that does not overflow may overflow with `rows * columns * sizeof *p`. Hence my preference for leading the multiplication with a `size_t` argument. IOWs, go from biggest needed type to maybe narrow ones rather than visa-versa. Of course having only 2 arguments of mixed types or all 3 as `size_t` allows for your preference without this concern. – chux - Reinstate Monica Nov 28 '19 at 03:26
  • @H.S. `int *arr = (int *)malloc(sizeof(int)*3);` May be right. So, malloc just ready memory space for value, and char save string pointer, int save num itself. Right? – 4rigener Nov 30 '19 at 13:24
  • @4rigener No, your understanding is completely wrong. Seems, you have confusion around the concept of pointers in `C`. A pointer type describes an object whose value provides a reference to an entity of the referenced type. That means, when you write - `int *p;`, here `p` is a pointer which can store address of a `int` type. Similarly, `char *p;`, here `p` is a pointer which can store address of a `char` type and you need to dereference a pointer when you want to access the data/value in the memory that the pointer points to. Also, don't cast the `malloc` return.... contd.. – H.S. Dec 02 '19 at 03:33
  • @4rigener Also, it seems you have confusion around array as well. Remember this - Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object ...... (c11 6.3.2.1p3). – H.S. Dec 02 '19 at 03:38
0

s1 is a char array. The name of the array (s1) is a pointer to char, and so you don't need & with scanf - because %s expects to read the character array.

char s1[10];
scanf("%s", s1);

Note that in this case you can also specify the address of s1 in scanf as well because in terms of address, s1, &s1[0], &s1 all point to the same address.

char s1[10];
scanf("%s", &s1); // work as well

arr is array of integer. It's correct that the name of the array (ie arr) is also a pointer (to int). But for scanf %d, which expect to read an integer, you have to provide the address of the integer you are reading. It's not an array, it's individual integer inside the array that scanf tries to read to - and you have to specify the address of it accordingly: &arr[1]

int arr[3] = (int *)malloc(sizeof(int)*3);
scanf("%d", &arr[1]);
artm
  • 17,291
  • 6
  • 38
  • 54
  • s1 = address, &s1 = address of address. Why is this same? – 4rigener Nov 28 '19 at 01:48
  • @4rigener: the answer is imprecise. `s1` is an array (that is, an object with an array type), and so `&s1` is a pointer to an object of an array type. `&s1` and `&s1[0]` point to the same place, but they are pointers of different types. The confusion comes from the fact that when you use `s1` as a function argument, or in many other contexts, it "decays" to a pointer to its first element. See [this answer](https://stackoverflow.com/a/1462103/1566221). – rici Nov 28 '19 at 02:38
0

When you scanf the array of chars (string), in your case s1, you don't need & because s1 stores a pointer to the first element (the element with index 0) of this array. With regard to dynamic allocation, malloc return value is a pointer to someplace in memory where your array will be stored. So your declaration should look like this:

int* arr = malloc(sizeof(int) * 3); 
scanf("%d", &add[1]); 
/* here you scanf only the second element of your massive,
 it is int so you have to put & there to pass a pointer */

If you want to initialize the whole massive you can write easy cycle for it. Iwould also recommend you to read some documentation about malloc and an article "calloc vs malloc".

Good luck :)

Sinking
  • 95
  • 8