1
int main()
{
    struct Student_struct {
        char name[40];
        int age;
        float grade;
    };

    struct Student_struct student;

    printf("---------------------Student-----------------------\n\n\n");
    student.name[] = "person";
    student.age = 20;
    student.grade = 7.5;
    
    return 0;
}

I got the following error: Expected expression before ']'

I know I can use strcpy(student.name, "person") or student.name[6] = "person", but why cannot just code it as student.name[] = "person"? What is the logic behind this?

Nejc Galof
  • 2,538
  • 3
  • 31
  • 70
Normye
  • 45
  • 4
  • Please edit your post to add code formatting and indention. – Lundin Jan 20 '22 at 14:07
  • 2
    `student.name[] = "person"` ==> `strcpy(student.name, "person");` don't forget to `#include ` – pmg Jan 20 '22 at 14:08
  • `student.name[6] = "person"` will not do what you want, and `student.name[] = "person"` is just incorrect syntax. – Fred Larson Jan 20 '22 at 14:08
  • 2
    Because `name[]` doesn't mean anything. `name` is already an array, what does `[]` add? – stark Jan 20 '22 at 14:10
  • In addition, you forget the `;` ... – Damien Jan 20 '22 at 14:10
  • The edit box includes tools at top, including `{ }`. Select the code section and click this tool and it will present that section as code instead of plain text. – ryyker Jan 20 '22 at 14:11
  • `...[] = "..."` only works in an initialization. It is special syntax that the compiler recognizes that does not extend to an assignment. The compiler writers/language designers could have made it so that a strcpy happens when you do an assignment, but they (wisely) choose not to introduce that additional complexity into the language. – William Pursell Jan 20 '22 at 14:11
  • 1
    Also note that `char name[6] = "person"` is an error. You need at least 7 characters to hold the string. – William Pursell Jan 20 '22 at 14:12
  • @ryyker Instead of giving new users free fish, how about learning them how to catch fish themselves, by letting them edit and fix obvious problems in their post themselves? – Lundin Jan 20 '22 at 14:16
  • @Lundin - FWIW I did both. (see comment) I wouldn't edit for more experienced users except for occasional typos. – ryyker Jan 20 '22 at 14:24
  • @ryyker Yeah well you rather left written instructions for how to catch fish, but the OP has yet to try them out themselves :) – Lundin Jan 20 '22 at 14:26
  • Have in mind the '\0' at the end of each string and also use ';'. – wajaap Jan 20 '22 at 14:40

5 Answers5

5

The array size is already defined in the struct declaration. Using square brackets after the declaration will access an element in the array, hence the error.

wquinoa
  • 122
  • 8
3

In C, you cannot assign whole arrays in run-time, there's no sound rationale for it, the language was simply designed that way. You can only set all items in an array during initialization. Similarly, you cannot return arrays from functions.

In this case the simple fix is strcpy(student.name, "person");

However, while you cannot assign whole arrays in run-time, you can assign whole structs. That's a possible work-around - by creating a temporary compound literal struct, we can do this:

student = (struct Student_struct){ .name = "person", .age=20, .grade=7.5 };
Lundin
  • 195,001
  • 40
  • 254
  • 396
2

I know I can use strcpy(student.name, "person") or student.name[6] = "person"

Fine, but do you know that the latter will not do what you expect?

An array is not a first class citizen in C. Full stop. You cannot have an array as the left member of an assignment simply because the C language does not allow it.

So when you use student.name[6] this is not an array of 6 character, but only the seventh character. It is allowed by the language, because a character is a numeric type and that a pointer can be converted to an int.

So student.name[6] = "person" first gets a pointer to the first element of the litteral string "person" converts(*) it to an integer value (which may already be implementation defined if pointers are larger than ints) and then tries to store that into a single char which invokes undefined behaviour if char is not unsigned. Is that really what you knew?


(*) In fact it is even worse because the language requires an explicit cast to convert a pointer to an arithmetic value so this code should at least raise a warning and warnings are not to be ignored. So as it violates a constraint the code is not valid C. Nevertheless, all common implementations that I know will either stop if asked to treat this warning as an error, or will continue the way I described above if not.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • 1
    "convert it to an integer value" No, the conversion you speak of only happens if the code is valid C. `student.name[6] = "person"` is a constraint violation of 6.5.16.1 so the compiler must generate a diagnostic message. And there's no telling what any binary generated by the compiler anyway does from there on. – Lundin Jan 20 '22 at 14:40
  • Specifically, see 6.5.4 constraints "Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast." – Lundin Jan 20 '22 at 14:41
  • @Lundin So does `student.name[6] = "person"` come down to converting a `char *` directly to a `char` (without going through `int` as answer above) and then 6.3.1.3 applies? (Potential UB when `char` is signed, else truncated) – chux - Reinstate Monica Jan 20 '22 at 14:45
  • @chux-ReinstateMonica No conversion takes place since the code isn't valid. The only implicit conversions of pointers that are allowed are those listed below 6.5.16.1 simple assignment. That includes conversions to/from void pointers and null pointers. – Lundin Jan 20 '22 at 14:47
  • More info here (I just updated it with this very clear quote from 6.5.4): ["Pointer from integer/integer from pointer without a cast" issues](https://stackoverflow.com/questions/52186834/pointer-from-integer-integer-from-pointer-without-a-cast-issues) – Lundin Jan 20 '22 at 14:49
  • @Lundin I think the "The only implicit conversions of pointers that are allowed ... " is more like "The only implicit conversions of pointers that are allowed during an assignment ..." - but I see your overall point. – chux - Reinstate Monica Jan 20 '22 at 14:51
  • @chux-ReinstateMonica No, it literally means what it says, 6.5.4 is from the definition of the cast operator. There is no situation where implicit pointer conversions are allowed in C outside assignment operations. – Lundin Jan 20 '22 at 14:54
  • @Lundin: You are right, I was aware of the warning but not of the constraint violation. I have tried to make explicit that the code is not valid C and that *only the most common implementations accept it*. Do you think it to be clear now? – Serge Ballesta Jan 20 '22 at 15:08
  • No they don't accept it, they gave you a warning (and then generated some binary goo of unknown characteristics). See [What must a C compiler do when it finds an error?](https://software.codidact.com/posts/277340) If you wish for strict conformance as well as compiler errors when the code breaks that conformance, you must use `-std=c17 -pedantic-errors`. – Lundin Jan 20 '22 at 15:12
  • @Lundin: I have already agreed that it was invalid code. Yet I pretend that MSVC, Clang and gcc, when not asked to treat warnings as errors, do generate the same code as if an explicit cast was given. The generated code is non sense, but with a predictible outcome. – Serge Ballesta Jan 20 '22 at 15:48
  • Assuming that the right operand was an integer value, it's not UB to store it in a signed `char` either. It is impl.defined. 6.3.1.3 "Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised." – Lundin Jan 20 '22 at 15:54
1

The lack of size is not the issue. Specifying a size won't help.

The problem is that you are trying to assign to an array. That's not allowed. You'll need to use strcpy or the like.

strcpy(student.name, "person");

In this particular case, you can initialize the array rather than assign to it.

struct Student_struct student = {
   .name  = "person",
   .age   = 20,
   .grade = 7.5
};
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    No, `strncpy` should never be used for any purpose. Please don't teach that to beginners. See [Is strcpy dangerous and what should be used instead?](https://software.codidact.com/posts/281518) – Lundin Jan 20 '22 at 14:13
  • @Lundin, True, I wouldn't use it cause you end up with an incomplete string. (I'm not sure if that's what the page says; I looked, but I didn't see the reason it gives after two dense pages!!!) Fixed. I added an alternate approach that works in this scenario to my answer while I was there. – ikegami Jan 20 '22 at 14:15
  • Scroll down to "What about strncpy?". It gives the background of the nasty incorrect rumours saying that `strncpy` is a safe version of `strcpy`, what the actual purpose of `strncpy` was and why it is too dangerous to allow in any C program. – Lundin Jan 20 '22 at 14:19
  • @ryyker Doesn't matter. If it was set to all zeroes and you passed the array size to `strncpy`, it will overwrite every single zero with data and not null terminate the string. The function is broken by design, or rather it was never meant to be used on null terminated strings to begin with. – Lundin Jan 20 '22 at 14:24
  • Not sure why it was deleted, but I had left a comment that lack of NUL temrination can be addressed by using `strncpy(dst, src, sz-1); dst[sz-1] = 0;`. But you're still left with an incomplete string. – ikegami Jan 20 '22 at 14:36
  • Yeah sure if you are aware of the flaw then you can use `strncpy` with a `-1` size. But it's oh-so easy to slip and forget that, since no other function in C works like that. – Lundin Jan 20 '22 at 14:45
  • @Lundin, No, I don't. Are you talking about the fact that a string needs at least one byte? But that's not specific to `strncpy`. – ikegami Jan 20 '22 at 14:51
1

It doesn't work simply because it is invalid syntax. If you want to do an initialization, you can do things like:

#include <stdio.h>

int
main(void)
{
        struct student {
                char name[40];
                int age;
                float grade;
        };

        struct student student = {
                "person",
                20,
                7.5
        };

        struct student student2 = {
                .name = "person",
                .age = 20,
                .grade = 7.5
        };

        printf("---------------------Student-----------------------\n\n\n");
        printf("%s\n", student.name);

        return 0;
}
William Pursell
  • 204,365
  • 48
  • 270
  • 300