Reputation: 21
I'm creating the * create Schedule () function to generate a schedule of the ScheduleData data type, but I get the error: incompatible type when assigning to type 'ScheduleData'. could some one help me how to solve this ?
In the Schedule * function createSchedule (), in the line schedule-> node [i] [j] = schData; error occurs
struct ScheduleData {
char *initials;
char *classroom;
char *teacher;
};
struct Schedule {
ScheduleData node[8][6];
};
Schedule *createSchedule() {
Schedule *schedule = malloc(sizeof(Schedule));
ScheduleData *schData;
for (int i = 0; i < 8; i++)
for (int j = 0; j < 6; j++) {
schData = malloc(sizeof(ScheduleData));
schData -> initials = NULL;
schData -> classroom = NULL;
schData -> teacher = NULL;
schedule->node[i][j] = schData;
}
return schedule;
}
Upvotes: 0
Views: 2448
Reputation: 18521
My answer is not an actual answer but an extension to Jonathan Leffler's answer:
I have read questions like yours very often. In most cases there is a misconception caused by comparing C and C++ with Java or C#:
In Java variables of primitive data types (like int
) hold values while values of class
data types hold references to objects.
"Reference" means that in the following program:
ScheduleData a = b;
a.initials = "ab";
b.initials = "xy";
... the same variable is accessed by the statements a.initials
and b.initials
.
However, C and C++ work differently:
You decide if a variable is a "pointer" (which more or less is a "reference") or if it is a value by using or not using an asterisk (*
) between the data type and the variable name. Example:
ScheduleData a, *b;
int c, *d, *e;
d = e;
In this example the variables a
and c
hold values, the variables b
, d
and e
hold references.
And just like in the Java example modifying the value d
points to will have the same effect as modifying the value e
points to because d
and e
are references to the same integer.
The first solution in Jonathan Leffler's answer proposes using values of the data type ScheduleData
instead of using references.
The second solution shows you how references are used. Avoiding references typically makes programming easier but references may be required if you want to do the equivalent of the following Java program:
ScheduleData x = node[4][2];
ScheduleData y = node[4][2];
node[4][2] = new ScheduleData();
/* x and y will be a reference to the same data structure but node[4][2]
* is a reference to a different data structure */
By the way
The program you have written is a C++ program, not a C program.
Unlke C++, C will not automatically recognize structure names as data types. Instead, you either have to define the data type using typedef
:
typedef struct _s_ScheduleData {
...
} ScheduleData;
... or you have to use the struct
keyword as part of the data type:
struct ScheduleData node[8][6];
Upvotes: 1
Reputation: 44340
How to fix “incompatible type” error in C?
You need to ask two questions:
What type is
schedule->node[i][j]
?
Answer: It is ScheduleData
What type is
schData
?
Answer: It is ScheduleData *
(i.e. pointer to ScheduleData
)
As the two variables have different types, you'll get a compilation error.
To fix it, you need to change the type of one of the variables to match the other.
From your code it seems that you would want to change schedule->node[i][j]
to be a ScheduleData *
. So all you need to do is:
struct Schedule {
ScheduleData *node[8][6];
// notice ^
};
BTW: You have tagged the question C but it seems that you use a C++ compiler. If you really want C++ then fix the tag. If you really want C, use a C compiler.
Upvotes: 2
Reputation: 141658
You can replace all the loops with a simple assignment:
Schedule *createSchedule(void) {
// ^^^^ use this to indicate no parameters
Schedule *schedule = malloc(sizeof(Schedule));
*schedule = (Schedule){0};
return schedule;
}
The (Schedule){0}
creates a temporary object and the initializer means any pointers will be set to null pointers.
If your compiler is very old then the assignment line can be replaced with Schedule blank = {0}; *schedule = blank;
.
Upvotes: 0
Reputation: 755064
Your struct Schedule
holds an array of actual struct ScheduleData
structures; you try to assign pointers to these structures, and the compiler objects. You don't need the malloc()
operations in the nested loops (or the assignment to schedule->node[i][j]
) — or you need ScheduleData *node[8][6];
. I recommend not using malloc()
in the loops.
Also, as Martin Rosenau noted in a comment, a C compiler does not generate a name Schedule
(in the 'ordinary identifiers' namespace) given a declaration struct Schedule { … };
— although a C++ compiler does. You need to add:
typedef struct Schedule Schedule;
typedef struct ScheduleData ScheduleData;
before you use the names Schedule
or ScheduleData
without the prior struct
. If you are writing C++ and not C, then you need to fix the tag o the question and you need to stop using malloc()
et al. If you must use malloc()
et al in C++, you will need explicit casts to convert the void *
to the correct type — the cast is unnecessary in C.
malloc()
Schedule *createSchedule(void)
{
Schedule *schedule = calloc(sizeof(Schedule), 1);
return schedule;
}
The use of calloc()
zeroes all the bytes in the structure, which will normally set all the pointers to NULL, etc. (The onus is on the calling code to check that a null pointer is not returned.) Alternatively:
Schedule *createSchedule()
{
Schedule *schedule = malloc(sizeof(Schedule));
if (schedule != NULL)
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 6; j++)
{
schedule->data[i][j].initials = NULL;
schedule->data[i][j].classroom = NULL;
schedule->data[i][j].teacher = NULL;
}
}
}
return schedule;
}
You could also use memset()
to zero the data provided by malloc()
, but using calloc()
will do that at least as efficiently.
malloc()
copiouslyChange the type of struct Schedule
to:
struct Schedule
{
ScheduleData *node[8][6];
};
Note that this uses a lot more memory (there is overhead for each allocation), and the structure is a lot harder to free (you need 49 calls to free()
instead of just 1).
.
or arrow ->
operators. They bind incredibly tightly; the space is unwarranted, aconventional, and makes your code harder to read.Schedule *createSchedule(void)
in both function declarations and definitions to indicate no arguments. C is not C++; the rules are different between the two. And being explicit about void
means the compiler will warn you about createSchedule(32, "pink elephants")
whereas it is not obliged to warn you about the abuse of the function if you do not specify the void
explicitly — you didn't create a prototype, just a function declaration, if you omit the void
.Upvotes: 3
Reputation: 9668
Schedule *createSchedule(void)
{
// make sure you cast the return arg of malloc!
Schedule *schedule = (Schedule*)malloc(sizeof(Schedule));
// no need to allocate each 6x8node, already done
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
schedule->node[j][i]->initials = NULL;
schedule->node[j][i]->classroom = NULL;
schedule->node[j][i]->teacher = NULL;
}
}
return schedule;
}
Alternatively, since every byte in a Schedule gets set to 0, you could just use memset()
after creation here:
Schedule *createSchedule(void)
{
// make sure you cast the return arg of malloc!
Schedule *schedule = (Schedule*)malloc(sizeof(Schedule));
memset(schedule, 0, sizeof(Schedule));
return schedule;
}
Upvotes: 2