Segmentation Fault before main
Asked Answered
Q

4

24

so I've been running into a problem where somehow my code is causing segmentation faults before any of my main actually runs. I've never had this happen before and I hardly have a quarter's worth of coding experience so I'm not sure if there's something I'm doing wrong. Everything compiles, at least on my computer, but upon running it my main is never reached.

Context: I'm trying to connect Vertices and Edges in an adjacency matrix and then use Prim's algorithm to build an MST, but that's for later. I built a header file, which originally contained only typdef calls for the structures and the functions. However, I switched the structure definitions to the header file because I was getting memory errors; hence why I think there's an issue with the structs.

graph.h:

//Leland Wong 00000897031
//graph header file



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

#ifndef GRAPH_H
#define GRAPH_H

typedef struct vertex
{
    double longitude;
    double latitude;
    char city[30];
    int index;
    int visited; //0: not visited, 1: visited, 2: visited
    struct edge* nexte;
    struct vertex* nextv;
    double projected;
}VERTEX;


typedef struct edge
{
    struct vertex* start;
    struct vertex* destination;
    double distance;
    struct edge* nexte;
}EDGE;


typedef struct graph
{
    struct vertex* list[756];
    struct edge* matrix[756][756];
}GRAPH;


/*
typedef struct vertex VERTEX;
typedef struct edge EDGE;
typedef struct graph GRAPH;
*/

double findDistance(VERTEX* v1, VERTEX* v2); //compute the distance between two locations
EDGE* connect(VERTEX* v1, VERTEX* v2); //connects two vertices and returns the connecting EDGE
GRAPH primMatrix(GRAPH *g); //connects all vertices using Prim's Algorithm in an adjacency matrix
//void lPrimConnect(VERTEX v); //connects all vertices using Prim's Algorithm in an adjacency list
EDGE* findSmallestEdge(VERTEX v, GRAPH *g); //finds the smallest EDGE connected to v


#endif

graph.c: contains the implementations of all my functions

//functions

//computes the distance between v1 and v2
double findDistance(VERTEX* v1, VERTEX* v2)
{
    printf("findDistance");
    double long1 = v1->longitude;
    double long2 = v2->longitude;
    double lat1 = v1->latitude;
    double lat2 = v2->latitude;
    double distance = 0;

    if(long1 < 0)
        long1 += 360;
    if(long2 < 0)
        long2 += 360;

    distance = powf((long1-long2), 2) + powf((lat1 - lat2), 2);
    distance = sqrt(distance);
    return distance;
}

//creates and returns an edge that connects v1 and v2
EDGE* connect(VERTEX* v1, VERTEX* v2)
{
    printf("connect");
    EDGE *new; 
    new->start = v1;
    new->destination = v2;
    new->distance = findDistance(v1, v2);
    return new;
}


//finds smallest edge connected to v in GRAPH g
EDGE* findSmallestEdge(VERTEX v, GRAPH *g)
{
    printf("findSmallestEdge");
    EDGE *tempe;
    int i, index;
    index = v.index;

    //set tempe equal to the first edge connected to v
    tempe = g->matrix[index][0];
    //find smallest edge connected to v
    for(i = 0; i < 756; i++)
    {
        if(g->matrix[index][i] -> distance < tempe->distance && g->list[index]->visited == 0)
        {
            tempe = g->matrix[index][i];
        }
    }
    return tempe;
}

//creates an MST out of GRAPH g using Prim's algorithm
GRAPH primMatrix(GRAPH *g)
{
    printf("primMatrix");
    GRAPH new; // = malloc(sizeof(GRAPH));
    EDGE *smallest;
    EDGE *tempe;
    int i, x;
    i = 1;
    x = 0;

    new.list[0] = g->list[0];   //add root node to MST
    g->list[0]->visited = 2;
    smallest = findSmallestEdge(*new.list[0], g); 
    new.matrix[0][smallest->destination->index] = smallest;
    //MST will contain all 756 nodes, so run this 755 times to ensure all nodes are reached
    while(i < 756)
    {
        x = 0;
        smallest = findSmallestEdge(*new.list[i], g);
        //i = number of vertices already reached
        while(x < i)
        {
            tempe = findSmallestEdge(*new.list[x], g);
            if(tempe -> distance < smallest -> distance)
            {
                smallest = tempe;
            }
            x++;
        }
        new.list[i] = smallest -> destination;
        smallest -> destination -> visited = 2;
        new.matrix[smallest->start->index][smallest->destination->index] = smallest;
        i++;
    }
    return new;
}

graphmatrixmain.c: my main function which builds the graphs

#include "graph.h"

int main(int argc, char* argv[])
{
    FILE *fp;
    static GRAPH g;
    char buffer[200];
    int i, j;
    char city[30];
    char *long1;
    char *lat1;

    if(argc == 1)
    {   
        printf("could not open file\n");
        return 0;
    }

    else
        fp = fopen(argv[1], "r");

    //read in line of data from txt file, build a new vertex, and insert into list
    while(fgets(buffer, 200, fp) != NULL)
    {
        VERTEX *new =  malloc(sizeof(VERTEX)); 
        printf("%s", buffer);
        sscanf(buffer, "%s %s %s", city, long1, lat1);
        //sscanf(buffer, "%[^\t]\t%[^\t]\t%s", city, long1, lat1); 
        printf("scanned in data\n");
        new->longitude = atof(long1);
        new->latitude = atof(lat1);
        new->index = i;
        g.list[i] = new;
        printf("%s: (%lf, %lf)", new->city, new->longitude, new->latitude);
        i++;
    }
    //create EDGE and make connects between every VERTEX in list
    for(i = 0; i < 756; i++)
    {
        for(j = 0; j < 756; j++)
        {
            g.matrix[i][j] = connect(g.list[i], g.list[j]);
            if(j == 0)
            {
                g.list[i]->nexte = g.matrix[i][j];
            }
        }
    }
    return 0;
}

In case its necessary, this is the file i'm reading in from: cities.txt it contains 756 entries total but as far as the code is concerned size shouldn't be relevant

Shanghai    121.47  31.23
Bombay  72.82   18.96
Karachi 67.01   24.86
Buenos Aires    -58.37  -34.61
Delhi   77.21   28.67
Istanbul    29  41.1
Manila  120.97  14.62
Sao Paulo   -46.63  -23.53
Moscow  37.62   55.75
Quartan answered 27/11, 2013 at 21:19 Comment(3)
Please compile with all warnings and debugging info (e.g. gcc -Wall -g). Improve the source till no warnings are given. Then, use a debugger. And tell more about your operating system, your compiler, the compilation command, etc...Adali
@dasblinkenlight actually answered it perfectly. the code currently compiles without any errors using -Wall I'm just running into a seg fault with my sscanf statement. I have updated the code to its current state. I now realize it's an error with my delimitersQuartan
I VTC as can no longer be reproduced because OP edited the code to fix the mistake as highlighted by the top answer, so this question now makes no sensePhallic
W
44

I've been running into a problem where somehow my code is causing segmentation faults before any of my main actually runs.

Usually, this means that the data structures that your main tries to place in the automatic storage area overflow the stack. In your situation, it looks like the GRAPH is a suitable suspect to do just that: it has a 2D array with 571536 pointers, which could very well overflow the stack before your main gets a chance to start.

One solution to this problem would be moving the GRAPH into the static area: since you allocate it in the main, it's going to be only one instance of it anyway, so declaring it static should fix the problem:

static GRAPH g;

You might also want to allocate it in the dynamic area using malloc, but in this case it probably does not matter.

Wafd answered 27/11, 2013 at 21:23 Comment(3)
And the solution is to allocate your GRAPH in heap (using malloc and friends).Adali
thank you so much, this was exactly the problem. I may not have time to implement this, but if I were to dynamically allocate the memory, would I declare a EDGE** and then as I add elements to the matrix call EDGE new = malloc(sizeof(EDGE))?Quartan
@user3040577 You could do it in several ways, but the easiest one is GRAPH *g = malloc(sizeof(GRAPH)); The size of the graph would be fixed in this situation. You could also allocate the matrix inside it dynamically - fully or partially. To allocate it partially, you'd use struct edge** matrix[756], and allocate individual rows as needed. To allocate it fully, you'd use struct edge*** matrix, allocate the top level with malloc, and then allocate all the individual rows with malloc, too.Wafd
F
6

Your problem is not "before main" as you state, but in the first few lines of your program. You are not initializing fp, so it could go anywhere. You also have memory errors in your loop with new. You need to copy the value into newly allocated memory.

You cannot see the printfs in your code because the output is buffered and your code crashes before the buffer is flushed. If you put exit(0) just after your printf("error");, you'll see that it works.

Fabric answered 27/11, 2013 at 21:31 Comment(0)
S
4

One possible reason for segmentation fault before main is the program was mistakenly linked with -shared option. I wasted a lot of time trying to debug it.

Straightout answered 6/5, 2020 at 3:33 Comment(2)
I was building a programming language using llvm, and I accidentally passed in -shared option when linking. Man, you saved me a day. ThxCassowary
I just had the same problem and it was because I had the --shared option on the command line string. I think Clang should warn about that if compiling an .exe.Bimetallism
M
2

I had faced "Segmentation fault occurs before main() execution begins" issue in my C++ code. Let me try to explain what my issue was and how I could solve it.

  1. A global/static class instance is present in code.
  2. Its constructor is invoked before main() begins.
  3. Inside constructor,in an error handling part, std::cerr is used to display error.
  4. std:cerr was not initialized when constructor was executed.
  5. Even though it says, if #include iostream is there before object is defined then std::cerr is initialized, it was not. https://en.cppreference.com/w/cpp/io/cerr
  6. If object of std::ios_base::Init is created before constructor, it ensures proper init and deinit of default c++ streams.
  7. why std::cerr was not initialized, In c++11 objects in iostream are init before other global objects. But in c++03, it is unspecified. Use std::ios_base::Init as a private member of class to ensure it is init before stream functions are executed. Is std::cout guaranteed to be initialized?
Medwin answered 29/10, 2019 at 8:36 Comment(2)
How is any of that relevant to a c question?Quasi
I tried to provide some generic info which is relevant to the error, thinking it might help someone else. Because when I got this issue and checked SO, this thread appeared first. Also error behavior was exactly like subject line of this question. I understand more clarity is needed in my post. Thank you for pointing it outMedwin

© 2022 - 2024 — McMap. All rights reserved.