2

I have this two different code writing in C. Both of them just try to assign value into structure. And i'm using cs50 library to help me to get string in simple way.

For the first code, when i'm trying to execute it got an error.

First Code:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

#define MaxStudents 5

typedef struct
{
    string name;
    int age;
    string gender;
}
student;

student students[MaxStudents];

int main(void)
{
    students[0] = {"Kevin Mahendra", 22, "Male"};
    students[1] = {"Wasis Sirutama", 22, "Male"};
    students[2] = {"Alief Dean", 22, "Male"};
    students[3] = {"Adwi Lanang", 21, "Male"};
    students[4] = {"Dhimas Kuncahyo", 22, "Male"};

    for (int i = 0; i < MaxStudents; i++)
    {
        printf("%s, %i %s", students[i].name, students[i].age, students[i].gender);
    }

}

Problem (first code):

sorting.c:19:19: error: expected expression
    students[0] = {"Kevin Mahendra", 22, "Male"};
                  ^
sorting.c:20:19: error: expected expression
    students[1] = {"Wasis Sirutama", 22, "Male"};
                  ^
sorting.c:21:19: error: expected expression
    students[2] = {"Alief Dean", 22, "Male"};
                  ^
sorting.c:22:19: error: expected expression
    students[3] = {"Adwi Lanang", 21, "Male"};
                  ^
sorting.c:23:19: error: expected expression
    students[4] = {"Dhimas Kuncahyo", 22, "Male"};

But for the second code, it works well without any error.

Second Code:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

#define MaxStudents 5

struct student
{
    string firstName;
    string lastName;
    int age;
};

int main(void)
{
    struct student kevin = {"Kevin", "Mahendra", 22};
    
    printf("%s %s, %i\n", kevin.firstName, kevin.lastName, kevin.age);
}

So what do you guys think the problem on my first code? What is expected expression means?

As you can see i'm just trying to assign value into the array of structures with only write it insdie {} just like i did in second code (But not an array). Please help me. Thank You.

klutt
  • 30,332
  • 17
  • 55
  • 95

5 Answers5

3

The problem is the difference between initialization and assignment. Initialization is basically an assignment done together with declaration.

When you want to assign a compound literal (for example {"Kevin Mahendra", 22, "Male"}) you need to cast it by putting (student) in front of it, but the cast is not necessary during initialization.

Note: Technically, it's not a cast. But it does look exactly like a cast, and many are calling it casting, either because of lack of knowledge or just because of sloppy language. I thought it was a cast before Eric Postpischil pointed it out.

Change to

students[0] = (student) {"Kevin Mahendra", 22, "Male"};

You can also do this:

student students[MaxStudents] = {
    {"Kevin Mahendra", 22, "Male"},
    {"Wasis Sirutama", 22, "Male"},
    {"Alief Dean", 22, "Male"},
    {"Adwi Lanang", 21, "Male"},
    {"Dhimas Kuncahyo", 22, "Male"},
};

Note that you can initialize arrays this way, like you can with structs. However, you cannot assign array this way afterwards. Take this code:

int arr[3];
arr = // Will not work no matter what you type here.

There's absolutely nothing you could write after arr = that would compile. You could try arr = {1,2,3} or arr = (int[3]) {1,2,3} but it will not work, because it's simply not allowed to assign to an array during any circumstances. However, it's possible with a workaround if you wrap the array in a struct.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • 1
    A compound literal is not a cast. – Eric Postpischil Jan 22 '21 at 13:42
  • @EricPostpischil No? It's look exactly the same. Isn't `(student)` a cast? If not, what is it? – klutt Jan 22 '21 at 13:43
  • 1
    @klutt, it does look like one, but it is not a cast. It is a compound literal. It is a separate syntantic construct. – koder Jan 22 '21 at 13:46
  • 2
    A compound literal is a compound literal. It provides an object and is its own thing in the C grammar. A cast is an operator that provides a conversion and appears separately in the C grammar. The fact that both use a type name in parentheses is irrelevant; `sizeof (int)` is not a cast of anything to an `int`. And `{ foo(); bar(); }` is a compound statement, but that does not mean that `{"Kevin Mahendra", 22, "Male"}` is a compound statement when it appears in a compound literal or an initialization. C grammar reuses the same symbols and partial constructions for different purposes. – Eric Postpischil Jan 22 '21 at 13:47
  • Lots of C operators and primary expressions use parenthesis symbols, including the cast operator and a bunch of others. The C syntax simply loves to use the `()` symbols for numerous often unrelated purposes. In case of compound literals the syntax is `( type-name ) { initializer-list }`. – Lundin Jan 22 '21 at 13:51
  • I'm new in doing coding, so thanks! But one question. Is it only for something that has a lot of value to assign? Because for example: i declare `int age;` then i can assign it in another line right `age = 10` ? So what's the different for this one? –  Jan 22 '21 at 13:55
  • @klutt is is the syntax used to define the compound literal. – 0___________ Jan 22 '21 at 13:57
  • @Kevinkun The difference is that `age=10;` is allowed but it's not allowed with structs. ;) – klutt Jan 22 '21 at 13:58
  • 1
    @Kevinkun The root of the problem is that you can't assign arrays with `=` in C. You can however assign structs with `=`. And the CS50 `string` thing is not an array anyway, but a pointer in disguise, not yet pointing at a valid array. – Lundin Jan 22 '21 at 14:00
  • @Lundin @klutt But why can i do this declare = `int array[Max];` then assign = `array[0] = 10; array[1] = 12; array[2] = 13;` ? I'm so sorry, i'm still confused. So i guess that's only happen for struct, right? –  Jan 22 '21 at 14:07
  • 1
    @Kevinkun Because in that case each item in the array is an `int`. In the CS50 case the `string` item is actually a pointer and it's supposed to point at an array. So it doesn't work pretty much for the same reason as `int arr1[Max]; int arr2[Max]; arr1 = arr2;` doesn't work. C simply doesn't allow that syntax and there's not really much of a rationale regarding why it doesn't. – Lundin Jan 22 '21 at 14:10
  • @Lundin: This question has nothing to do with arrays. There are no arrays in the `struct`, the string literals in the desired values are converted to `char *`, and the OP’s code only attempts to assign elements of arrays, not arrays. `cs50.h` defines `string` to be `char *`. The root of the problem is that `{…}` is not C grammar for a structure value, so the OP’s attempt to assign values to structures fails. – Eric Postpischil Jan 22 '21 at 14:18
  • @EricPostpischil `string` could be whatever you want it to be. Everything from C++ to minimal underwear. But surely not a character pointer hidden behind a typedef because that would be an incredibly stupid thing to do. – Lundin Jan 22 '21 at 14:23
  • @Lundin I'm not sure if you're sarcastic, but in cs50, a string is actually typedefed in that stupid way. – klutt Jan 22 '21 at 14:27
3

There is a difference between initialization (second code) and the assignment (first code)

This syntax is only valid if you initialize the object, not when you assign. As structs are copied when assigned you can use compound literals for that:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

#define MaxStudents 5

typedef struct
{
    string name;
    int age;
    string gender;
}
student;

student students[MaxStudents];

int main(void)
{
    students[0] = (student){"Kevin Mahendra", 22, "Male"};
    students[1] = (student){"Wasis Sirutama", 22, "Male"};
    students[2] = (student){"Alief Dean", 22, "Male"};
    students[3] = (student){"Adwi Lanang", 21, "Male"};
    students[4] = (student){"Dhimas Kuncahyo", 22, "Male"};

    for (int i = 0; i < MaxStudents; i++)
    {
        printf("%s, %i %s\n", students[i].name, students[i].age, students[i].gender);
    }
}

https://godbolt.org/z/KvE7G1

0___________
  • 60,014
  • 4
  • 34
  • 74
1

The second piece of code is an initialization:

struct student kevin = {"Kevin", "Mahendra", 22};

Here you define a variable and provide an initial value. Here the part on the right of the = is parsed as having type struct student.

In the first code there is only an assignment

students[0] = {"Kevin Mahendra", 22, "Male"};

And in an assignment the type of the variable assigned to is not used in the evaluation of the right hand side. So the compiler can not know what {"Kevin Mahendra", 22, "Male"} is supposed to be.

This can be solved by using a compound literal (which essentially looks like a cast):

students[0] = (student){"Kevin Mahendra", 22, "Male"};

Or you can just initialize the students array when you define it:

student students[MaxStudents] = {
    {"Kevin Mahendra", 22, "Male"},
    {"Wasis Sirutama", 22, "Male"},
    {"Alief Dean", 22, "Male"},
    {"Adwi Lanang", 21, "Male"},
    {"Dhimas Kuncahyo", 22, "Male"},
};
koder
  • 2,038
  • 7
  • 10
0

You can only initialize a struct like that when it is created. struct student kevin = {"Kevin", "Mahendra", 22}; will work just fine, but try struct student kevin; kevin = {"Kevin", "Mahendra", 22};; it will give an error.

When you create the array, it will put an uninitialized struct at each index, meaning you can't initialize it afterwards. [EDIT] As klutt mentioned, you can set the values with {} with a cast.

mediocrevegetable1
  • 4,086
  • 1
  • 11
  • 33
  • "*You can only initialize a `struct`*" not just only structs. This holds for variables of any type. – alk Jan 22 '21 at 13:37
  • 1
    Actually, since this is a global array, it IS initialized to zero. – klutt Jan 22 '21 at 13:56
0

For completeness the ugly one:

#include <string.h>

  ...

  student students[MaxStudents];

  memcpy(students, 
    (student[MaxStudents])
    {
      {"Kevin Mahendra", 22, "Male"},
      {"Wasis Sirutama", 22, "Male"},
      {"Alief Dean", 22, "Male"},
      {"Adwi Lanang", 21, "Male"},
      {"Dhimas Kuncahyo", 22, "Male"},
    },
    sizeof (student[MaxStudents])
  );
alk
  • 69,737
  • 10
  • 105
  • 255