1
#include <stdio.h>

struct Person
{
    char name[50];
    int roll;
    float marks;
} s[5];

int main()
{
    printf("Enter information of students:\n");

    for (int i = 0; i < 5; ++i)
    {
        s[i].roll = i + 1;
        printf("\nFor roll number %d,\n", s[i].roll);
        printf("Enter name: ");
        scanf("%s", s[i].name);
        printf("Enter marks: ");
        scanf("%f", &s[i].marks);
    }
    printf("\nDisplaying Information:\n");

    for (int i = 0; i < 5; ++i)
    {
        printf("\nRoll number: %d\n", s[i].roll);
        printf("Name: ");
        printf("%s\n", s[i].name);
        printf("Marks: %.1f\n", s[i].marks);
    }

    return 0;
}

I am learning C programming from the website, however I don't understand why does scanf with name we don't need & in front of s[i].name, while s[i].marks there is a & before.

Hope the question is clear, and thank you for reading my post.

(https://www.programiz.com/c-programming/examples/information-structure-array)

Rob
  • 14,746
  • 28
  • 47
  • 65
Currycatlover
  • 99
  • 1
  • 1
  • 7
  • 1
    Hello. `scanf` expects a pointer to place value into. `s[i].name` is a pointer, `s[i].marks` - isn't. – user14063792468 Aug 09 '21 at 17:18
  • 1
    Do you understand what the `&` does? Basically, it indicates the address of a variable should be used, not the value of the variable itself. In your example for `s[i].name` you don't need the `&` because `name` is `char[]` and an unindexed array is effectively a pointer. – h0r53 Aug 09 '21 at 17:19
  • @user14063792468 @h0r53 Thank you so much. So in case if `s[i].roll`, which isn't a pointer, I also don't need the **&** when using `scanf`, right? – Currycatlover Aug 09 '21 at 17:22
  • 1
    @Brandon TW : No, use "scanf("%d", &s[i].roll);", since roll is not a pointer It is just like marks, except an int vs a float--neither are pointers (a "pointer" is aka an "address"). name declared as "char name[50]" (50 chars allocated) is a pointer to a char (since it's already a pointer, there is no need to use "&" which means "the address of"). name2 declared as "char *name2" would also be a pointer to a char (but zero chars are allocated). name3declared as "char name3" would be just a char, in which case you would need the &, but only 1 char is allocated so that's another issue. – Andrew Aug 09 '21 at 18:07
  • 1
    When you use the expression `s[i].name` as an argument to the function `scanf`, that array [decays](https://stackoverflow.com/q/1461432/12149471) to a pointer. – Andreas Wenzel Aug 09 '21 at 18:49
  • 1
    So much text for so simple question. I wonder. – user14063792468 Aug 09 '21 at 19:32
  • 1
    Always check the return value of `scanf()`. and NEVER USE `scanf("%s"....` whoever teaches you to program this way: Don't listen to him, he doesn't understand programming. – 12431234123412341234123 Aug 09 '21 at 19:42
  • 1
    @user14063792468 *So much text for so simple question* Yup, that's `scanf` for you. Definitely not a paragon of clarity, consistency, and user-friendliness. – Steve Summit Aug 09 '21 at 20:15
  • 1
    @SteveSummit Definetly is not. But I prefer `scanf` family functions over all other input functions. C++ `streams` not even close. – user14063792468 Aug 09 '21 at 21:34

1 Answers1

3

In C passing by reference means passing an object indirectly through a pointer to it.

To be able to change an object (and not a copy of the value of it) the function scanf needs to get it by reference.

In this call

scanf("%s", s[i].name);

the array designator name is implicitly converted to pointer to its first element. This call in fact is equivalent to

scanf("%s", &s[i].name[0]);

So using the passed pointer to the first element of the array and the pointer arithmetic the function can change any element of the array because they altogether are passed by reference.

To change the scalar object marks you need also to pass it by reference

scanf("%f", &s[i].marks);

Here is a simple demonstrative program

#include <stdio.h>

void f( int *p )
{
    *p = 20;
}

int main(void) 
{
    int x = 0;
    
    printf( "Before call of f x = %d\n", x );
    
    f( &x );

    printf( "After  call of f x = %d\n", x );
    
    int a[] = { 0 };
    
    printf( "Before call of f a[0] = %d\n", a[0] );
    
    f( a );

    printf( "After  call of f a[0] = %d\n", a[0] );
    
    return 0;
}

The program output is

Before call of f x = 0
After  call of f x = 20
Before call of f a[0] = 0
After  call of f a[0] = 20

In this call

f( a );

the array designator a is implicitly converted to pointer to its first (and in this case single) element. You could write also

f( &a[0] )
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335