0

So i decided to solve a problem from some C book. Handled all the errors gcc compiler told me to handle, so now program compiles with no error. However, when I run the executive, after the input, it says "Segmentation fault". What does it mean and how do I fix it?

I supposed that is because I implement discrete function to count the sum, then tried to wrtie a code in just main(). it worked okay, but still.

I am curious of what are the reasons of this mistake, and why it appears when i decide to use function?

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

double summation(long* N);

int main(void)
{
    printf("summation of squares of first N numbers\n");
    printf("enter N\n");
    long* N;
    *N = 0;

    scanf("%li\n",N);

    double su;
    su = summation(N);
    printf("The summ equals %.lf\n", su);
    return 0;
}

double summation(long* N)
{
    double S = 0;
    int i;

    for (i = 1; i <= *N; i++)
        S = S + pow(i, 2);
    return S;
}

thanks in advance.

aapts
  • 19
  • 4
  • 2
    it means "undefined behavior" somewhere in your code. A syntactically correct C program is accepted by the compiler, this is by no means a guarantee the program is correct. –  Jul 20 '18 at 08:29
  • 1
    btw, `*N = 0;` is the culprit, `N` doesn't point to a usable `long` variable, it's just an uninitialized pointer. You're trying to write to some "random" location that probably doesn't even exist. –  Jul 20 '18 at 08:30
  • Why are you using a `long *` at all? – Mat Jul 20 '18 at 08:31
  • 3
    Declare N as `long` and give scanf the pointer by using the address operator & (`scanf(..., &N);` – Ctx Jul 20 '18 at 08:32
  • @Ctx removing asterisk and giving scanf &N worked, the problem dissapeared. But why so? If i do "int* j"; and then use just i, isn't that the same as if i define "int i" and then use the address operator &j? – aapts Jul 20 '18 at 08:36
  • @FelixPalmen at some point, when I used 'long *N' with no initializations as ' long N = 0' gcc said that i try to use uninitialized variable. Either way, I added these pointer operators, and then it stopped barking at me. But how in the universe 'long *N = 0' does not point to any variable? – aapts Jul 20 '18 at 08:43
  • Consider using a memory debugging tool such as valgrind. – Ra'Jiska Jul 20 '18 at 08:48
  • @Mat because I want to try out different types of variables. I see `int64` lots of times when i look at digital filters in MCU C code, and using `long` seems rather good idea. Why not? – aapts Jul 20 '18 at 08:48
  • I have the impression that you are working with pointers, even without knowing it. Try to remove every asterisk from your code, and get it working from there. Once this work, you might get acquainted with pointers. – Dominique Jul 20 '18 at 08:48
  • @Arman if this makes it more clear, you can try `long *N; long var; N = &var;scanf("%li", N);`. You have to assign something to `N` before you use it. `*N = 0` is a use of `N` and not an assignment to `N`. Assignment to `N` looks like `N = ...;` – Ajay Brahmakshatriya Jul 20 '18 at 08:49
  • Because `int *j` declares a variable that store an address to an `int`, not an actual `int`, there is no storage for it. `*j` try to load an `int` at the address but you get an warning since the *address* is uninitialized. `int i; int* j = &i; *j = 1` will set `i` through the pointer `j`. – Piezoid Jul 20 '18 at 08:49
  • @Arman: the problem is using a `long *` not a `long` when you don't need it. And then failing to allocate memory for it. – Mat Jul 20 '18 at 08:49
  • @Dominique I read some articles and paragraphs in books about pointers, and for a while, managed to make my codes work by adding asterisks here and there. I know of them, but hardly understand logics, yea. In this case, code started working after I removed `*` from everywhere – aapts Jul 20 '18 at 08:54
  • @Arman adding asterisks _here and there_ to make your code work does not sound good. You need to understand what a pointer is. – Jabberwocky Jul 20 '18 at 08:55
  • The _minimal_ change to get your code working would be to allocate memory for your long pointer: `long* N = malloc(sizeof long);`. – Ctx Jul 20 '18 at 08:58

1 Answers1

2

The problem is here:

long* N;          // N points nowhere
*N = 0;           // you deferecence a pointer that points nowhere
                  // which most likely will result in a segfault
scanf("%li\n", N);

This is correct:

long N;
N = 0;            // this line is somewhat useless BTW, because
                  // N will be modified in the line below anyway
scanf("%li\n", &N);
...
su = summation(&N);

Or even better:

su = summation(N);
...

double summation(long N)   // no need to pass the pointer to N
{                          // just pass N
  double S = 0;
  int i;

  for (i = 1; i <= N; i++)
    S = S + pow(i, 2);
  return S;
}

You need to read the chapter dealing with pointers in your C text book.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • Why the second option is better? Why passing var, not the address of var? – aapts Jul 20 '18 at 09:00
  • @Arman lets say that it is _more straight forward_. – Jabberwocky Jul 20 '18 at 09:02
  • 1
    @Arman For a simple problem use a simple solution, hence using pointers only complicates the summation. – hetepeperfan Jul 20 '18 at 09:03
  • So I can remove the line `N = 0;` or type `long N = 0;`, I understand that i change the value immediately. But it is told, that i need to __initialize__ every value. And as I had understood that, I need to give some value to any variable as soon as i define this value. Am i right? – aapts Jul 20 '18 at 09:06
  • @Arman well, not quite. It's good practice to initialize your variables, but as `N` will be modified by `scanf` anyway you don't need to initialize `N` beforehand, but it doesn't harm either. Simple example: `int x; ...; x = foo*bar;` is OK, you don't need to initialize `x` upon declaration because it will be assigned by this statement anyway: `x = foo*bar;`. – Jabberwocky Jul 20 '18 at 09:10