0

I have been sitting on this problem for 3 hours and I would appreciate it if you could guide me, We have the student structure that contains a name, and points to an array of pointers of size 3 only and it should point to 3 different teachers (random of course), when I try to return the pointer to the random array from teacherArray, within the operation AttemptTeacherToStudents, in practice, nothing is received, And the pointer remains empty. I would really appreciate the help

My structs:

typedef struct
{
    char name[20];
    struct ClassRoom * myClass;
}Teacher;

typedef struct {
    char * name;
    struct ClassRoom *myClassRoom;
    struct Teacher *myTeachers[3];
    
}Student;

int InitalizeStudent2(Student *student, char *name, Teacher *teacher)
{
    student->name= name;
    *student->myTeachers = teacher;
    printf("%s", name);

    return 0;
}

The problem is with this code:

Teacher ** teacherArray(Teacher * teachers)
{
    Teacher *randomArray[3];
    int i = 0;
    while (i<3)
    {
        Teacher * teacher=teachers + (rnd() % 6);
        randomArray[i++] = teacher;

    }
    return randomArray;
}
void AttempTeacherToStudents(Teacher* teachers)
{
    Student * allOfMYStudents = (Student *)malloc(5 * sizeof(Student));
    for (int i = 0; i < 5; i++)
    {
        char name[255];
        sprintf(name, "Student_%d", 100 + i);
        char *newName = _strdup(name);
        InitalizeStudent2(&allOfMYStudents[i], newName, *teacherArray(teachers));
    }

}


Teacher** InitalizeGenrealTeacher()
{
    char allTeachers[6][6] = { "Teach1\0", "Tech2\0", "Tech3\0","Tech4\0", "Tech4\0", "Tech5\0" };
    Teacher * myTeachers =(Teacher*) calloc(6 , sizeof( Teacher));

    for (int i = 0; i < 6; i++)
    {
        InitalizeTeacher(&myTeachers[i], allTeachers[i]);
        

    }
    return myTeachers;
    
}


int main()
{
    srand(time(NULL));
    Teacher*pMyTeacher = InitalizeGenrealTeacher();
    for (int i = 0; i < 6; i++)
    {

        printf("%s \n", pMyTeacher[i].name);
    }
    

    AttempTeacherToStudents(pMyTeacher);
}

enter image description here

the problem is, why the pointer of "myTeachers" is empty at [1][2]? why does cell number [0] not null too?

Bubi
  • 27
  • 4
  • 1
    Please enable all compiler warnings. For GCC use `-Wall -Wextra -pedantic`. – Gerhardh Aug 09 '22 at 16:23
  • `teacher = (rnd() % 6);` While picking 3 out of 6 it is rather likely to get duplicate results. – Gerhardh Aug 09 '22 at 16:25
  • 2
    `return randomArray;` This should trigger some compiler warning. You return the address of a non-static local variable. Its lifetime ends after you return from that function. Any attempt to access the content of that array afterwards, is illegal. – Gerhardh Aug 09 '22 at 16:26
  • Besides that, you do not show enough code. We don't see prototypes and implementations of the functions you call or how the shown function is called. Please read [How-to-ask](https://stackoverflow.com/help/how-to-ask) and edit your question to include a [MCVE](https://stackoverflow.com/help/mcve) – Gerhardh Aug 09 '22 at 16:28
  • Does this answer your question? [Return address of local variable in C](https://stackoverflow.com/questions/8743411/return-address-of-local-variable-in-c) – Gerhardh Aug 09 '22 at 16:30
  • Thanks for all comments, i edited my questions with all the code – Bubi Aug 09 '22 at 16:34
  • `"Teach1\0"` That does not fit into an array for 6 `char`s – Gerhardh Aug 09 '22 at 16:36
  • 1
    `strcpy(student->name, name);` at this point `student->name` is uninitialized and so that's [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior) (ie. it will probably crash). You need to allocate memory to `student->name`. I'd recommend making Student and Teacher consistent whether `name` is stored as a pointer or an array. – Schwern Aug 09 '22 at 16:39
  • Still not compileable. Still throwing lots of warnings. `return myTeachers;` You return `teacher*` while `teacher**` is expected. No idea if the hidden function `InitializeTeacher` does some ugly hack to make it look correct. – Gerhardh Aug 09 '22 at 16:40
  • `*student->myTeachers = teacher;` That only assigns a single teacher (yes, that illegal address from earlier...) to the first element of the pointer array. All the other pointers stay uninitialized. – Gerhardh Aug 09 '22 at 16:43
  • The program crashed on the InitalizeStudent2(), I dont know how to fix it, because im giving him an address of the array.. any suggestions? – Bubi Aug 09 '22 at 16:46
  • As I wrote twice: That address is illegal to access. Check the question I linked. There you can read how to avoid returning local addresses. – Gerhardh Aug 09 '22 at 16:48
  • I did some Changes, Please take a look :) – Bubi Aug 09 '22 at 17:01
  • You ignored all my comments – Gerhardh Aug 10 '22 at 07:19

1 Answers1

0

First, turn on compiler warnings. They will give you a lot of extra information and avoid a lot of frustration. How you do that depends on the compiler/IDE you're using.


int InitalizeStudent2(Student *student, char *name, Teacher *teacher)
{
    // student->name is uninitialized
    strcpy(student->name, name);

    // student->myTeachers is an existing array of 3 elements, yet you're assigning an existing array to it.
    // student->myTeachers is `struct Teacher*` which does not exist, it should be `Teacher*`
    *student->myTeachers = teacher;

    return 0;
}

student->name is defined as char *name. Unlike char name[20], you need to allocate memory for the student's name. I would recommend using strdup for that, and to make Teacher and Student consistent as to how they store strings.

student->myTeachers is declared as struct Teacher *myTeachers[3]. There is no struct Teacher only Teacher. typedef struct { ... } Teacher only declares Teacher.

student->myTeachers is allocates an array of 3 elements, yet you already have an allocated array of Teachers. If you're going to add an existing array to Student, declare it as Teacher *myTeachers to just store the pointer and assign it with student->myTeachers = teacher.

Note that the teacher passed to InitalizeStudent2 is from teacherArray and has already been deallocated. Read on.


Teacher ** teacherArray(Teacher * teachers)
{
    // This will be deallocated when the program returns.
    Teacher *randomArray[3];
    int i = 0;
    while (i<3)
    {
        // I'm not sure what the rand() % 6 is for.
        Teacher *teacher = teachers + (rand() % 6);
        randomArray[i++] = teacher;

    }
    return randomArray;
}

Teacher *randomArray[3] allocates automatic memory. This memory will be deallocated once teacherArray returns; that means something can overwrite that memory. It's very convenient, but it means if you return it something might overwrite it. Instead, you need to allocate the memory with malloc or calloc and then free it later. Alternatively, the caller can allocate the array and pass it into teacherArray.

Otherwise, it's unclear what this function is trying to do.


Teacher** InitalizeGenrealTeacher()
{
    // It's not necessary to add the \0 to strings.
    // But do remember to allocate an extra byte for the \0.
    char allTeachers[6][6] = { "Teach1\0", "Tech2\0", "Tech3\0","Tech4\0", "Tech4\0", "Tech5\0" };

    // There's no need to cast calloc or malloc.
    Teacher * myTeachers = (Teacher*) calloc(6 , sizeof( Teacher));

    for (int i = 0; i < 6; i++)
    {
        InitalizeTeacher(&myTeachers[i], allTeachers[i]);
    }

    // The function returns `Teacher **` but myTeachers is `Teacher *`.
    return myTeachers;
}

While C strings are terminanted by a null byte, "" adds the null byte for you; it's just "Teach1". You do need to remember the null byte when allocating memory, so "Teach1" needs 6 bytes. Since these are fixed size strings, you can let the compiler figure it out with char allTeachers[6][].

The function returns Teacher **, which would be an array of Teacher pointers. But myTeachers is a Teacher *, which is an array of Teacher structs.

InitalizeTeacher is missing from your code.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • I made some changes. Most of the warnings that the compiler gives me are simply incomprehensible to me.. When I DEBUG the program, I do get some value back from the teacherArray program, I would appreciate it if you could look at the picture in the question I edited – Bubi Aug 09 '22 at 17:11
  • @Bubi "*the problem is, why the pointer of "myTeachers" is empty at [1][2]? why does cell number [0] not null too?*" If you're referring to that portion, that is explained in the answer and there are many problems. There is no `struct Teacher`, it is `Teacher`. `Teacher *myTeachers[3]` defines and allocates an array of 3 Teachers, but you're assigning a brand new array to that; you probably want just a pointer `Teacher *myTeachers;` to just store the array of Teachers. `teacherArray` returns memory that is deallocated. You have to fix all that and understand the warnings. – Schwern Aug 09 '22 at 17:45
  • @Bubi You will probably get a value back from `teacherArray`, but the memory has already been deallocated. The program is free to overwrite the memory later. C eventually use that memory for something else. So while your array may be there now, there's no guarantee it will be there later. – Schwern Aug 09 '22 at 17:51
  • I did a callloc array for the Teacher is it stil a wrong way? – Bubi Aug 09 '22 at 18:26
  • @Bubi Maybe, I'd have to see your code. Please update your question, or post it as a Github Gist. – Schwern Aug 10 '22 at 03:09