1
#include <stdio.h>
#include <stdlib.h>

typedef struct Ogrenciler {
    int no;
    char adi[50];
    char soyadi[50];
    double vize;
    double final;
    double notu;
} Ogr;

int ogrenciSayisi = 0;

void KayitEkle(Ogr *ogrenci) {
    int simdikiOgr = ogrenciSayisi;
    if (ogrenciSayisi == 0) {
        ogrenciSayisi++;
        ogrenci = (Ogr *) malloc(ogrenciSayisi*sizeof(Ogr));
    } else {
        ogrenciSayisi++;
        ogrenci = (Ogr *) realloc(ogrenci, ogrenciSayisi * sizeof(Ogr));
    }
    printf("No:");
    scanf("%d", &ogrenci[simdikiOgr].no);
    printf("Adi:");
    scanf("%s", ogrenci[simdikiOgr].adi);
    printf("Soyadi:");
    scanf("%s", ogrenci[simdikiOgr].soyadi);
    printf("Vize:");
    scanf("%lf", &ogrenci[simdikiOgr].vize);
    printf("Final:");
    scanf("%lf", &ogrenci[simdikiOgr].final);
    ogrenci[simdikiOgr].notu = (ogrenci[simdikiOgr].vize * 0.4) + (ogrenci[simdikiOgr].final * 0.6);
    printf("Notu: %lf", ogrenci[simdikiOgr].notu);
    printf("\n\n");
    printf("Adi: %s\nNo: %d\nVize: %lf\nFinal: %lfNotu: %lf\n",
           ogrenci[simdikiOgr].adi, ogrenci[simdikiOgr].no, ogrenci[simdikiOgr].vize, ogrenci[simdikiOgr].final,
           ogrenci[simdikiOgr].notu);
}

int main() {
    int c;
    while (c != 5) {
        printf("\n1-\tYeni Kayit Ekle\n2-\tKayit Sil\n3-\tKayitlari Listele\n4-\tOrtalama Hesapla\n5-\tCikis\n");
        scanf(" %d", &c);
        Ogr *ogrenci;
        switch (c) {
            case 1:
                KayitEkle(ogrenci);
                break;
            case 2:
                KayitSil(ogrenci);
                break;
            case 3:
                KayitListele(ogrenci);
                break;
            case 4:
                OrtHesapla(ogrenci);
                break;
            case 5:
                printf("Cikiliyor");
                break;
            default:
                printf("Gecerli bir girdi yapiniz\n");
                break;
        }
    }

    return 0;
}

As u can see, I use malloc() and realloc() for my typedef struct and I'm able to enter only one entry. When I tried adding a new entry (switch case: 1) it doesn't work and crashes after this section:

printf("No:");
scanf("%d", &ogrenci[simdikiOgr].no);

At first, I tried I used calloc(ogrenciSayisi*10*sizeof(Ogr)) but it was created only one space. After that, in the debugger (CLion's) after realloc section, ogrenci pointer becomes a null pointer.

Edit: I'm not trying to return a value. As I know (int a) equals (int a[ ]) so KayitEkle(ogrenci) and void KayitEkle (Ogr ogrenci) seems legit to me. And my ogrenci should be empty in the first place so (Ogr *ogrenci=NULL) is correct as you said right?

Edit2: In malloc section 10 is a mistake. I fixed it. I was trying something and I forgot to delete it.

  • 2
    Unrelated to your problem, but you use `c` without initialization. That means its value is *indeterminate* and will seem almost random. Don't do that. – Some programmer dude May 07 '18 at 08:33
  • 3
    As for your problem, arguments to functions are passed *by value*. That means they are *copied*, and modifying the copy will not change the original. Do some research about *emulating pass by reference in C*. Oh, and don't forget to initialize the variable `ogrenci` too! – Some programmer dude May 07 '18 at 08:36
  • 4
    Possible duplicate of [How to return a pointer as a function parameter](https://stackoverflow.com/questions/5286453/how-to-return-a-pointer-as-a-function-parameter) – Ken Y-N May 07 '18 at 08:36
  • 1
    What @Someprogrammerdude said, was that your `ogrenci` variable is changed only locally when you realloc. `main` has its own copy which is unchanged. That is why you have problems. You need to understand how variables and pointers work or you will have this problem many times. Read https://stackoverflow.com/questions/5286453/how-to-return-a-pointer-as-a-function-parameter – Prof. Falken May 07 '18 at 09:43
  • Also worth noting, your `realloc` will actually reallocate to a *smaller* location, which does not appear to be what you intended to do. You have a 10x multiplier in the `malloc` for some reason. Additionally, you should *always* check the return value from `malloc` and `realloc` to confirm that they have actually returned memory to you. – David Hoelzer May 07 '18 at 09:53
  • regarding: *I used calloc(ogrenciSayisi*10*sizeof(Ogr)) but it was created only one space* The function `calloc()` has two parameters, not just one (unlike `malloc()`), Suggest you read/understand the MAN page for each function you want to use; especially the syntax for the function(s). – user3629249 May 08 '18 at 23:03
  • When reading about the syntax of the C library functions: `malloc()` and `calloc()` pay attention to the `type` of each parameter and the `type` of the returned value. Also, always check (!=NULL) the returned value to assure the operation was successful – user3629249 May 08 '18 at 23:07
  • When calling `realloc()`, do not assign the returned value directory to the target pointer. Rather assign to a `temp` pointer, then check (!=NULL). If not NULL, then assign to the target pointer. Otherwise when `realloc()` fails, the target pointer will be assigned NULL, so the pointer to the allocated memory will be overwritten, resulting in a memory leak. – user3629249 May 08 '18 at 23:10
  • when calling any of the heap allocation functions: `malloc` `calloc` `realloc`, the returned type is `void*` which can be assigned to any pointer. Casting just clutters the code making it more difficult to understand, debug, etc – user3629249 May 08 '18 at 23:12
  • it is common usage that `#define`, `enum` and `typedef` names be all caps with an underscore separating the root words. – user3629249 May 08 '18 at 23:13
  • when calling any of the `scanf()` family of functions, 1) always check the returned value (not the parameter values) to assure the operation was successful. 2) when using the input/format specifiers '%s' and '%[...]' always include a MAX FIELD WIDTH modifier that is one less than the width of the input buffer. This is because those input/format specifiers always append a NUL byte to the input. (and to avoid any possibility of a buffer overflow, Such overflow results in undefined behavior – user3629249 May 08 '18 at 23:17
  • regarding, in `main()`, `int c; while (c != 5) {` The variable `c` is not initialized, so will contain what ever trash was on the stack, at its' location. Suggest: `int c = 0;` – user3629249 May 08 '18 at 23:25
  • regarding, in `main()`, `Ogr *ogrenci; switch (c)` this will create a new local variable `ogrenci` each time through the loop. Most likely that is not what you want, Suggest either `static Ogr *ogrenci = NULL;` or moving the declaration to before the `while()` loop – user3629249 May 08 '18 at 23:31
  • Note: in `main()` if the variable `ogrenci` is initialized to NULL, then then in function: `KayitEkle()` the first several lines of code can be simplified to: `int simdikiOgr = ogrenciSayisi; !ogrenciSayisi++; ogrenci = (Ogr *) realloc(ogrenci, ogrenciSayisi * sizeof(Ogr));` because the `realloc()` function properly handles when the original pointer contains NULL – user3629249 May 08 '18 at 23:35
  • regarding: `scanf(" %d", &c);` several of the input/format specifiers consume/discard leading 'white space' ( see the MAN page for the details) so no need to have a leading space in the format string when the input/format specifier is '%d' – user3629249 May 08 '18 at 23:38
  • for ease of readability and to honor the page right margin (column 72 or 80) (especially useful when printing the source code), long statements should be broken at/before the right margin. For that long string that contains the menu, suggest at each (other than first) '\n' to use: ...\n" ".... – user3629249 May 08 '18 at 23:42
  • here is an example of checking the returned value when calling `scanf()` : if( scanf("%d", &ogrenci[simdikiOgr].no) != 1 ) { fprintf( stderr, "scanf failed to input 'no'\n"); }` – user3629249 May 08 '18 at 23:45
  • when exiting `main()`, before the `return 0;` statement, call `free()` for each of the allocated memory pointers, Do not produce sloppy code that expects the OS to cleanup after the program. – user3629249 May 08 '18 at 23:47

2 Answers2

1

You pass ogrenci pointer by value to KayitEkle(), you modify it's value inside it, yet not return it's modified value to main(). You need to pass ogrenci value using a pointer (ie. KayitEkle(&ogrenci)) or return the new value to the called (ie. ogrenci = KayitEkle(ogrenci)). Example below is with the latter. ogrenci pointer is inside the while loop, so it will be reinitialized every time the loop runs, probably you meant to put it outside of the loop so it's value is preserved. Local variables have undefined (read: any) value without initialization, so you need to explicitly initialize ogrenci to NULL, if you need. See Initialization. You don't need to check for ogrenciSayisi == 0 when ogrenci == NULL, because realloc(NULL, ...) is equal to malloc(...). See realloc.

#include <stdio.h>
#include <stdlib.h>

typedef struct Ogrenciler {
    int no;
    char adi[50];
    char soyadi[50];
    double vize;
    double final;
    double notu;
} Ogr;

int ogrenciSayisi = 0;

// or void KayitEkle(Ogr **ogrenci) and then use *ogrenci
Ogr *KayitEkle(Ogr *ogrenci) {
    int simdikiOgr = ogrenciSayisi;

    ogrenciSayisi++;
    ogrenci = realloc(ogrenci, ogrenciSayisi*sizeof(Ogr));

    printf("No:");
    scanf("%d", &ogrenci[simdikiOgr].no);
    printf("Adi:");
    scanf("%s", ogrenci[simdikiOgr].adi);
    printf("Soyadi:");
    scanf("%s", ogrenci[simdikiOgr].soyadi);
    printf("Vize:");
    scanf("%lf", &ogrenci[simdikiOgr].vize);
    printf("Final:");
    scanf("%lf", &ogrenci[simdikiOgr].final);
    ogrenci[simdikiOgr].notu = (ogrenci[simdikiOgr].vize * 0.4) + (ogrenci[simdikiOgr].final * 0.6);
    printf("Notu: %lf", ogrenci[simdikiOgr].notu);
    printf("\n\n");
    printf("Adi: %s\nNo: %d\nVize: %lf\nFinal: %lfNotu: %lf\n",
           ogrenci[simdikiOgr].adi, ogrenci[simdikiOgr].no, ogrenci[simdikiOgr].vize, ogrenci[simdikiOgr].final,
           ogrenci[simdikiOgr].notu);
    return ogrenci;
}

int main() {
    int c = 0;
    Ogr *ogrenci = NULL;
    while (c != 5) {
        printf("\n1-\tYeni Kayit Ekle\n2-\tKayit Sil\n3-\tKayitlari Listele\n4-\tOrtalama Hesapla\n5-\tCikis\n");
        scanf(" %d", &c);
        switch (c) {
            case 1:
                ogrenci = KayitEkle(ogrenci);
                break;
            case 2:
                ogrenci = KayitSil(ogrenci);
                break;
            case 3:
                ogrenci = KayitListele(ogrenci);
                break;
            case 4:
                ogrenci = OrtHesapla(ogrenci);
                break;
            case 5:
                printf("Cikiliyor");
                break;
            default:
                printf("Gecerli bir girdi yapiniz\n");
                break;
        }
    }

    // it's nice to free things
    free(ogrenci);

    return 0;
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
0

There are many mistakes. If you want to dynamically allocate memory with your function. A pointer of pointer must be used e.g. The instructions on the realloc line are also not correct, because if your re-allocation fails, you overwrite the old memory address and the pointer takes the same value as NULL.

And without getting off topic. You should also take precautions with the scanf function if you enter anything other than what the format expects (e.g. characters instead of numbers or vice versa), it is sure that the program will behave indeterminately, so you should anticipate this scenario.

sambia39
  • 35
  • 9