Thread: Problems with Malloc

  1. #1
    Registered User
    Join Date
    Apr 2020
    Posts
    6

    Problems with Malloc

    I'm trying to use malloc to increase the size of 3 dynamic arrays, but it keeps crashing as soon as it enters the first for loop. count is a pointer to an int holding the total nomber of records there should be, fname and lname are dynamic arrays holding names equal to count, and grades is another dynamic array holding the grades.

    Code:
     void addRecs(int *count, char **fname, char **lname, float *grades)
    {
    
      *count = *count + 1;
    
      //reallocate older stuff
      char **tempf = realloc(fname, *count * sizeof *tempf);
      for (int i = 0; i < *count - 1; i++) {
        tempf = realloc(fname, 20 * sizeof *tempf);
      }
    
      char **templ = realloc(lname, *count * sizeof *templ);
      for (int i = 0; i < *count - 1; i++) {
        templ = realloc(lname, 20 * sizeof *templ);
      }
      float *tempg = realloc(grades, *count * sizeof *tempg);
    
      //allocate space for newest
      templ[*count - 1] = (char *) malloc(20 * sizeof *lname[*count - 1]);
      tempf[*count - 1] = (char *) malloc(20 * sizeof *fname[*count - 1]);
    
      free(fname);
      free(lname);
      free(grades);
    
      fname = tempf;
      lname = templ;
      grades = tempg;
    
      printf("Add a record\n");
      scanf("%s %s %f", &fname[*count - 1][0], &lname[*count - 1][0],
            &grades[*count - 1]);
      int i;
      for (i = 0; i < *count; i++) {
        printf("First Name: %s, Last Name: %s, Score: %.2f \n", &fname[0],
               &lname[0], grades);
      }
    }
    Last edited by Salem; 04-09-2020 at 10:20 PM. Reason: removed eyebleed crayola

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    F .
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Have you considered using an array of a structure instead of what you're currently doing?

    Please show your complete program, I really need to see how you defined the variables you are using for your parameters and how you are actually calling that function.

  4. #4
    Registered User
    Join Date
    Apr 2020
    Posts
    6
    Quote Originally Posted by jimblumberg View Post
    Have you considered using an array of a structure instead of what you're currently doing?
    I wish I could but this is for an assignment so I'm required to use pointers. Here is the rest of the code:
    Code:
    #include<stdio.h>#include<string.h>
    #include<stdlib.h>
    #include<stdlib.h>
    
    //prints all records in the same order they were entered
    void printRecs(int *count, char **fname, char **lname, float *grades)
    {
      printf("count: %d\n", *count);
      //for loop to print all the arrays
      int i;
      printf("count: %d\n", *count);
    
      for (i = 0; i < *count; i++) {
        printf("loop count: %d\n", i);
        printf("First Name: %s, Last Name: %s, Score: %.2f \n", &fname[0],
               &lname[0], grades);
      }
    }
    
    void addRecs(int *count, char **fname, char **lname, float *grades)
    {
    
      *count = *count + 1;
    
      //reallocate older stuff
      char **tempf = realloc(fname, *count * sizeof *tempf);
      for (int i = 0; i < *count - 1; i++) {
        tempf = realloc(fname, 20 * sizeof *tempf);
      }
    
      char **templ = realloc(lname, *count * sizeof *templ);
      for (int i = 0; i < *count - 1; i++) {
        templ = realloc(lname, 20 * sizeof *templ);
      }
      float *tempg = realloc(grades, *count * sizeof *tempg);
    
      //allocate space for newest
      templ[*count - 1] = (char *) malloc(20 * sizeof *lname[*count - 1]);
      tempf[*count - 1] = (char *) malloc(20 * sizeof *fname[*count - 1]);
    
      free(fname);
      free(lname);
      free(grades);
    
      fname = tempf;
      lname = templ;
      grades = tempg;
    
      printf("Add a record\n");
      scanf("%s %s %f", &fname[*count - 1][0], &lname[*count - 1][0],
            &grades[*count - 1]);
      int i;
      for (i = 0; i < *count; i++) {
        printf("First Name: %s, Last Name: %s, Score: %.2f \n", &fname[0],
               &lname[0], grades);
      }
    }
    
    int main()
    {
      int choice = 1;
      //ask user for total count of students, must be between 5 and 15
      int temp = 0;
      int *count = &temp;
      while ((*count > 15) || (*count < 5)) {
        printf
            ("Please indicate number of records you want to enter (min 5, max 15): ");
        scanf("%d", count);
      }
    
      //read in all the data for the students
      char **lname = (char **) malloc(*count * sizeof *lname);
      for (int i = 0; i < *count; i++) {
        lname = (char *) malloc(20 * sizeof *lname);
      }
    
      char **fname = (char **) malloc(*count * sizeof *fname);
      for (int i = 0; i < *count; i++) {
        fname = (char *) malloc(20 * sizeof *fname);
      }
    
      float *grades = (float *) malloc(*count * sizeof *grades);
    
      int i;
      printf
          ("Please input records of students (enter a new line after each record), with following format first name last name score\n");
      for (i = 0; i < *count; i++) {
        scanf("%s %s %f", &fname[0], &lname[0], &grades);
      }
    
      //display menu and switch inside a loop for selection
      //printf("Print records (press 1)\nSearch by first name (press 2)\nSearch by last name (press 3)\nSort by score (press 4)\nSort by last name (press 5)\nFind Max Score (press 6)\nFind Min Score (press 7)\nExit the program (press 0)\n");
    
    
      while (choice != 0) {
        printf("Enter choice: ");
        scanf("%d", &choice);
        switch (choice) {
        case 0:
          break;
        case 1:
          printRecs(count, fname, lname, grades);
          break;
        case 2:
          addRecs(count, fname, lname, grades);
          break;
        default:
          printf("Please only enter a number from 0 to 7\n");
          break;
        }
    
      }
    
    }
    Last edited by Salem; 04-09-2020 at 10:21 PM. Reason: removed crayola

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    I wish I could but this is for an assignment so I'm required to use pointers.
    So? Then why not a pointer to a structure?

    Now look at this function:
    Code:
    void addRecs(int *count, char **fname, char **lname, float *grades)
    {
    ...
    First question where in that function (or in main()) are you trying to retrieve an array of grades for each student?

    Second question in main() you defined fname as an array of C-strings (**fname) and you called the function like:
    Code:
    addRecs(count, fname, lname, grades);
    So do you realize that you can't change where *fname points? You need to pass the address of *fname to the function if you want to change where the pointers are pointing.

    Also why are you "adding" students in both your function and in main().

    Next you shouldn't be casting the return value of malloc(), that cast can hide problems.

    Lastly for now, when posting code please use code tags and post your text as plain text.

  6. #6
    Registered User
    Join Date
    Apr 2020
    Posts
    6
    Sorry I should have specified. My teacher specifically said no structs and no arrays.

    I retrieve the grades and names in main starting on line 92. I'm adding students in both the main function and the addRecs function because its part of the assignment.

    Can you elaborate on the hiding problems bit? I'm new to C and don't understand what issues it hides.

    On the code tags, I thought I put the code inside tags I messed up, sorry about that. New to the forum and the "before posting" page is down.

    Thanks for taking time to help me out, I really do appreciate it!

    My bad on the formatting,

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    My teacher specifically said no structs and no arrays.
    Okay, but you do realize that you are using arrays, right?

    And by the way in C strings are also arrays of char, no getting around this is you want to use a string.

    I retrieve the grades and names in main starting on line 92.
    But you're only retrieving one grade per student, is that what you want?

    And as I said you can't change where the pointers point for your array of strings inside that function (as the function is now written).

    By using dynamic allocated arrays of dynamically allocated strings you are really making things much more difficult, perhaps you should talk to your instructor for more guidance?

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Stop using such an awful font ffs.
    Copy-as-text from your IDE, and/or paste-as-text in your browser.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Apr 2020
    Posts
    6
    He specified the variables he wanted us to use and gave us these, and said we should not add any other arrays or structs.

    I do want only 1 array per student.

    Could you explain how to change where the pointers point to for my array inside the function where I try to "add" a record (and whats wrong w/ mine currently)?

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by bandicoot
    He specified the variables he wanted us to use and gave us these, and said we should not add any other arrays or structs.
    I hope that this is merely a learning exercise in order to demonstrate as a negative example why this is a cumbersome way of doing things. If he does indeed write code like this for real himself, then he probably isn't a good programmer.

    Now, onto to your code. What I suggest is this: start with a reduced version of the problem. For example, instead of a record consisting of first name, last name, and grade, pretend that each record consists of just a first name. Then write the code under this assumption. Compile and test. When you're pretty sure you have it working with just first names, include last name into the record. Modify the code under this assumption. Compile and test. When you're pretty sure you have it working with first names and last names, include grade into the record, etc.

    This way, you'll be fixing just one problem at a time. If you've made a mistake with how you're handling first names, that's the mistake you have to fix. You don't have to replicate it for last names, then find out that your fix was wrong and you have to do over twice.

    EDIT:
    By the way, you don't have to do that "reallocate older stuff" thing. You do need to reallocate for the new record, but that's just one call of realloc for each item in the record (i.e., you reallocate the dynamic array for that item so that it can accommodate the new record), and then allocating space for the first and last names. You definitely do not need to call free when you add a record.
    Last edited by laserlight; 04-09-2020 at 11:30 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    I don't know why you have an addRecs being called in your menu selection.

    Aside from the initial allocation in main, and the subsequent input, there seems to be no reason to change the data.
    So all of the malloc/realloc inside functions isn't necessary.

    Besides, asking newbies to realloc a 2D array of pointers from within a function is a big ask.

    Most of the rest was just fixing the array notation when trying to access your pointers.
    Code:
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    //prints all records in the same order they were entered
    void printRecs(int *count, char **fname, float *grades)
    {
      printf("count: %d\n", *count);
      //for loop to print all the arrays
      int i;
      for (i = 0; i < *count; i++) {
        printf("loop count: %d\n", i);
        printf("First Name: %s, Score: %.2f \n", fname[i], grades[i]);
      }
    }
    
    void addRecs(int *count, char **fname, float *grades)
    {
      printf("Add a record\n");
      scanf("%s %f", fname[*count], &grades[*count]);
      *count = *count + 1;
      printRecs(count, fname, grades);
    }
    
    int main()
    {
      int choice = 1;
      //ask user for total count of students, must be between 5 and 15
      int temp = 0;
      int *count = &temp;
      while ((*count > 15) || (*count < 5)) {
        printf
            ("Please indicate number of records you want to enter (min 5, max 15): ");
        scanf("%d", count);
      }
    
      //read in all the data for the students
      char **fname = malloc(*count * sizeof *fname);
      for (int i = 0; i < *count; i++) {
        fname[i] = malloc(20 * sizeof *fname[i]);
      }
    
      float *grades = malloc(*count * sizeof *grades);
    
      int i;
      printf("Please input records of students (enter a new line after each record), "
              "with following format first name last name score\n");
      for (i = 0; i < *count; i++) {
        scanf("%s %f", fname[i], &grades[i]);
      }
    
      //display menu and switch inside a loop for selection
      printf("Print records (press 1)\n"
             "Search by first name (press 2)\n"
             "Search by last name (press 3)\n"
             "Sort by score (press 4)\n"
             "Sort by last name (press 5)\n"
             "Find Max Score (press 6)\n"
             "Find Min Score (press 7)\n"
             "Exit the program (press 0)\n");
    
      while (choice != 0) {
        printf("Enter choice: ");
        scanf("%d", &choice);
        switch (choice) {
        case 0:
          break;
        case 1:
          printRecs(count, fname, grades);
          break;
        case 2:
          addRecs(count, fname, grades);
          break;
        default:
          printf("Please only enter a number from 0 to 7\n");
          break;
        }
      }
    }
    
    $ ./a.out 
    Please indicate number of records you want to enter (min 5, max 15): 3
    Please indicate number of records you want to enter (min 5, max 15): 5
    Please input records of students (enter a new line after each record), with following format first name last name score
    fred 1
    barney 3
    betty 4
    wilma 10
    bambam 0
    Print records (press 1)
    Search by first name (press 2)
    Search by last name (press 3)
    Sort by score (press 4)
    Sort by last name (press 5)
    Find Max Score (press 6)
    Find Min Score (press 7)
    Exit the program (press 0)
    Enter choice: 1
    count: 5
    loop count: 0
    First Name: fred, Score: 1.00 
    loop count: 1
    First Name: barney, Score: 3.00 
    loop count: 2
    First Name: betty, Score: 4.00 
    loop count: 3
    First Name: wilma, Score: 10.00 
    loop count: 4
    First Name: bambam, Score: 0.00 
    Enter choice:
    Oh, and if your compiler barfs on the uncast malloc with messages like "cant convert void* to...", then stop using C++ to compile your C program.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  12. #12
    Registered User
    Join Date
    Apr 2020
    Posts
    6
    Thanks for looking over my code.

    My current menu is wrong, I commented it out but forgot to remove it before posting my code here. I'm supposed to do a bunch of varying tasks, but this is the hardest one. I'm supposed to keep the variables I already have in there and then reallocate space so that the user can input another student after they input their original ones. I know its a bit of a dumb task, but its part of the assignment.

    This is what the menu is supposed to have for context:

    Print records (press 1)
    Add a new record (press 2)
    Delete record(s) (press 3)
    Search by last name (press 4)
    Sort by score (press 5)
    Sort by last name (press 6)
    Find median score (press 7)
    Exit the program (press 0)
    Last edited by bandicoot; 04-09-2020 at 11:54 PM. Reason: added menu

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Are you expected to add more records than the initial 5 to 15?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  14. #14
    Registered User
    Join Date
    Apr 2020
    Posts
    6
    Yeah, after the initial 5-15 I'm supposed to add one at a time if they pick the second option, and later delete them if they select the third option.

  15. #15
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Extending a 2D array using realloc is no small feat.
    Because realloc can move the memory, you need to make sure you capture the possibly changed pointer.

    If you're dealing with only one at once, you can use normal function pass by value and return.
    But if you're trying to extend several parallel arrays all at once, it's messy!

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    char **extender1( char **fname, int *count ) {
      char **tmp = realloc(fname, sizeof(*fname)*((*count)+1));
      if ( tmp ) {
        count += 1;
        return tmp;
      } else {
        return fname;
      }
    }
    
    // https://wiki.c2.com/?ThreeStarProgrammer
    void extender2( char ***fname, int *count ) {
      char **tmp = realloc(*fname, sizeof(**fname)*((*count)+1));
      if ( tmp ) {
        count += 1;
        *fname = tmp;
      }
    
      // if you wanted to actually use the 2D array, it would be
      // (*fname)[i]
    }
    
    int main()
    {
      int count = 10;
    
      //read in all the data for the students
      char **fname = malloc(count * sizeof *fname);
      for (int i = 0; i < count; i++) {
        fname[i] = malloc(20 * sizeof *fname[i]);
      }
    
      // extend inline
      char **tmp = realloc(fname, sizeof(*fname)*(count+1));
      if ( tmp ) {
        fname = tmp;
        count += 1;
      }
    
      // extend via a function, one way
      fname = extender1( fname, &count );
    
      // extend via a function, another way
      extender2( &fname, &count );
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. a couple of malloc problems
    By cAsk in forum C Programming
    Replies: 2
    Last Post: 04-18-2016, 12:20 AM
  2. Problems with malloc
    By Zachary Lewis in forum C Programming
    Replies: 7
    Last Post: 02-18-2008, 06:45 AM
  3. Problems with pointers and malloc()
    By Deirdre in forum C Programming
    Replies: 3
    Last Post: 10-28-2007, 04:20 PM
  4. malloc problems
    By garion in forum C Programming
    Replies: 5
    Last Post: 12-30-2005, 03:57 PM
  5. Malloc problems
    By PunkyBunny300 in forum C Programming
    Replies: 5
    Last Post: 10-01-2003, 07:27 PM

Tags for this Thread