Home > Back-end >  Segmentation Fault (core Dumped) when working with pointers in C
Segmentation Fault (core Dumped) when working with pointers in C

Time:03-14

So im currently trying to get my program to read a user input ( a double), and store said input in the heap using pointers in C. I allocate 40 bytes to the heap, and the program runs fine up until the program prompts me to enter an input to be stored, At which point after providing the first input, I get the segmentation fault. I know it may come as an out of bounds error, or an error with improper dereferencing, but I can't quite find where I did that. Any help would be greatly appreciated.

  • Edit: It's become clear my question was a bit confusing, so some clarifications: The goal of the program is to take an unspecified number of grades, starting with an initial heap size 40 bytes (project requirement), and whenever the heap is full, it is copied into a new one of size 80 bytes, with the old 40 bytes being freed. This continues until all grades have been entered.

  • Placing count as a parameter to defAlloc was a mistake, not quite sure why I put that there to begin with but that his since been removed.

  • The allocation aspect of this has been fixed and now works properly, im mainly having an issue with accessing elements within the heap and altering them ( grade Scanner Method)

  • Sorry for the messy code or confusing wordings, im new to both pointer usage and arithmetic as well as posting on stack overflow. Thank you for the responses.

  • an example of input and output: Input: 81.0 43.0 25.0 73.5

Output: Allocated 40 Bytes to the heap at 0x8d8010 stored 81 in the heap at 0x8d8010

This Repeats for each value until full heap or reaching a sentinel value.

I don't want to give away a whole bunch of information regarding input/output and the project as this is a school assignment (For academic dishonesty purposes) but essentially the issue im having is coming up in the gradeScanner method where im trying to read input and assign it to ptr, ptr 1, etc. Whatever it may be something is causing a segmentation fault

void defAllocator(double **grades);
  void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade);
  int main() {
      int allocCount;
      int gradeCount;
      double myGrade;
     double *grades;
     printf("Enter a list of grades below where each grade is seperated by a newline Character");
     printf("After the last grade is entered, enter a negative value to end the list");
     defAllocator(&grades);
     if(grades == NULL) {
         printf("null");
     }
     else
         printf("hello");
     gradeScanner(gradeCount, allocCount, grades, myGrade);
 
 }
 
 void defAllocator(double **grades) {
     double *arr = (double*)malloc(40);
     if(arr != NULL) {
     printf("Allocated 40 bytes at the heap at %p\n", grades);
     }
     else
         printf("failed to allocate array");
     *grades = arr;
 }
 
 void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade) {
     int i =0;
     while(i != 5){
         if(scanf("%f", myGrade) > 0 && gradeCount == 0) {
             *grades = myGrade;
             gradeCount  ;
             printf("%p\n", grades);
             printf("%p\n", gradeCount);
             i  ;
         }
 
         else if(scanf("%f", myGrade) < 0) {
             i = 5;
         }
         else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
             *(grades   gradeCount) = myGrade;
         }
 
     }
 }

CodePudding user response:

Lets get some simple bits going first. The allocation of the grades array

You have

   void defAllocator();

then

   double myGrade;
   double *grades = &myGrade;
   defAllocator(grades);

and finally

void defAllocator(double *grades, int count) {
    grades = (double*)malloc(40);
    printf("Allocated 40 bytes at the heap at %p\n", grades);
}

there is almost nothing correct about any of these lines.

  • the function declaration (first line) does not match the actual function
  • I think you expect the function to update the 'grades' pointer passed to it somehow. Setting 'grades' to point to a random double beforehand is not useful. Just init it to NULL if you want to be neat
  • you then call allocate with only one argument even though its supposed to take 2. Its clear you intended to work out how many you needed by asking the user and passing that in, but for some reason you gave up on that plan
  • the allocate function at the moment does not check that malloc worked
  • the allocate function discards the returned pointer. It places it in the grades argument but thats a local copy.
  • the allocator chooses 40 bytes , with no relationship to the size of what it it allocating

first - what should the allocation function look like. I would make it return the pointer to the allocated memory

double *defAllocator(int count) {
    double *arr = (double*)malloc(sizeof(double)*count);
    if(arr != NULL)
       printf("Allocated 40 bytes at the heap at %p\n", arr);
    else 
       printf("failed to alllocate array");
    return arr; 
}

Still keeping the hard coded max size. But make it a constant so that you can use it elsewhere , for example to check that not too many results have been entered.

So now we get

 const int GRADE_ARRAY_SIZE = 40; 
 double *defAllocator(int count);
 ....
 double *gradeArray = defAllocate(GRADE_ARRAY_SIZE);

If you want, as an exercise say, to pass the pointer in and have it updated by the allocater, then you need this (its an example of c-style 'pass by reference')

void defAllocator(double **gradeArrayPtr, int count) {
    double *arr = (double*)malloc(sizeof(double)*count);
    if(arr != NULL)
       printf("Allocated 40 bytes at the heap at %p\n", arr);
    else 
       printf("failed to alllocate array");
    *gradeArrayPtr = arr;
}

now do

 const int GRADE_ARRAY_SIZE = 40; 
 void defAllocator(double **gradeArrayPtr, int count);
 ....
 double *gradeArray = NULL;
 defAllocate(&gradeArray, GRADE_ARRAY_SIZE);

others have pointed out errors in the scanner code, but without the allocater working nothing else will work either

CodePudding user response:

OK now the allocator is fixed lets look at the scanner code. We have

  int allocCount;
  int gradeCount;
  double myGrade;
  double *grades;
  gradeScanner(gradeCount, allocCount, grades, myGrade);

and the actual function.

 void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade) {
     int i =0;
     while(i != 5){
         if(scanf("%f", myGrade) > 0 && gradeCount == 0) {
             *grades = myGrade;
             gradeCount  ;
             printf("%p\n", grades);
             printf("%p\n", gradeCount);
             i  ;
         }
 
         else if(scanf("%f", myGrade) < 0) {
             i = 5;
         }
         else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
             *(grades   gradeCount) = myGrade;
         }
 
     }
 }

Note, you code invokes multiple lots of Undefined Behavior so its hard to know exactly what is happening, I am guessing, But in fact tryi\ing to reason about UB is a big mistake.

Lets look at this piece

   if(scanf("%f", myGrade) > 0 && gradeCount == 0)
  • gradeCount is not initialized so its almost certainly not 0 (UB)
  • scanf returns the number of things it scanned not the value it found. So here its either one (%f) or 0 if there was invalid input. I suspect you are seeing if a value > 0 was entered. Maybe not, but its not clear
  • you must pass a pointer to the value you want to read into, you are only passing in the value (myGrade) (UB - very strong likelyhood of dying here)

OK so thats always false (gradeCount != 0) so we move onto the next

         else if(scanf("%f", myGrade) < 0) {
             i = 5;
         }
  • this reads the next value from input, its not looking again at the same input, not clear if that what you want.
  • scanf only returns 0,1 or EOF in the case. Maybe you are trying to detect EOF (that is usually -1)
  • you must pass a pointer to the value you want to read into, you are only passing in the value (myGrade) (UB, very string likely hood of death again)

Anyway this is false because of the test for < 0 that only happens at EOF

So now we get to

         else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
             *(grades   gradeCount) = myGrade;
         }
  • this reads the next value from the input, did you mean that?

  • same errror with 'myGrade' instead of '&myGrade' (very bad UB)

  • but scanf might return 1 and gradeCount is almost certainly > 0 (50/50 chance given that its unitialized) .If this did test to true we do

       *(grades   gradeCount) = myGrade;
    

more normally this is written

        grades[gradeCount] = myGrade;

well gradeCount is uninitialized so this is very bad UB. Note that if this had worked myGrade will be unitialized too (also UB)

So

Plus

  • why the 5
  • do you intend to keep reareading when an input misses a test
  • Related