Working on implemeting graphs for a CS class project I declared these two structures
typedef struct person {
char name[128];
int age;
} Person;
typedef struct graph {
int knots;
int adjacencies[500][500];
Person personList[500];
} Graph;
void insertPerson(Graph *g, Person p) {
g->personList[knots] = p;
(g->knots)++;
}
void writeAdjacencies(Graph g) {
for(int i = 0; i < MAXDIM; i++) {
for(int j = 0; j < MAXDIM; j++) {
printf("%d ", g.adjacencies[i][j]);
}
printf("\n");
}
}
Everything is fine except that when trying to create a menu function (reading inputs and then deciding whether to add new person or remove existing one, etc...) passing a graph pointer and then using it's pointed instance seems to be generating a segmentation fault.
void checkInput(int input, Graph *g) {
int temp;
char tempName[128];
if(input == 1 ) {
printf("\n Name: ");
scanf(" %[^\n]", tempName);
printf("%s\n", tempName);
Person p;
strcpy(p.name, tempName);
/* takes graph pointer a person and just adds person to personList and increases knots
it's working as intended
*/
insertPerson(g, p);
/* Goes through each element in the matrix and prints it
this is the one causing problems
*/
writeAdjacencies(*g);
}
}
The code is working fine until the moment I pass *gas an argument - that is if I put the writeAdjacencies(*g) under a comment it does not cause any trouble.
I don't get what is the issue here? I feel as if I'm using pointers like I did so far throughout the year and it worked. Maybe I could be passing a null pointer? But I did inialize it in the main function I think.
main.c :
Graph graph;
for(int i = 0; i < MAXDIM; i++) {
for(int j = 0; j < MAXDIM; j++) {
g.adjacencies[i][j] = 0;
}
}
g.knots = 0;
checkInput(0, &g);
Any help is welcomed!
EDIT: included both missing functions
Ignoring the potential buffer overflows from your scanf code, your Graph structure is way too large for the stack (containing 250,000 integers). Use dynamic memory allocation instead. E.g.:
typedef struct {
int** adjacencies;
int n;
} Graph;
void graph_init(Graph* g, int n) {
g->n = n;
g->adjacencies = malloc(n * sizeof(int*));
for (int i = 0; i < n; ++i) {
g->adjacencies[i] = malloc(n * sizeof(int));
}
}
void graph_free(Graph* g) {
for (int i = 0; i < g->n; ++i) {
free(g->adjacencies[i]);
}
free(g->adjacencies);
g->n = 0;
}
Related
we've been working on some structs, and decided that we wanted to make them dynamic so we could run a function that would basically make AREASIZE amount of struct areas and store them in our area *array, instead of us having to manually make a block of code with for example 10, 100 or 1000 struct areas and subsequently *Narea amount of subareas.
We've been stuck a couple of hours, and thought it might be more productive to ask where our logic is shit, cuz we cannot seem to find it. The code just crashes in the nested for loop of our create areas function.
Our logic:
we have a struct *array called area, which has a struct *array inside called subareas.
we pass the struct *array area to our function create_areas
create_areas uses the arrow operator to parse through our struct *array areas[i] and then our struct *array subareas[j]. And then fills up the values of our subareas.
before exiting we also assign the other value in our struct *array area, which is its average
In our heads would lead to our struct *array area being filled with 5x areas.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MARGIN 70
#define MARGIN2 30
#define SIZE 5
#define NAREA 4
#define AREASIZE 5
typedef struct subarea
{
int co2_cost, time;
double average, sensorData[SIZE];
} subarea;
typedef struct area
{
subarea *subarea_array[NAREA];
double average;
} area;
void create_areas(area *area_array[NAREA]);
void sensor_data_start(area *area, double start_var);
int main(void)
{
int co2_counter = 0, time_counter = 0;
int day_counter = 0;
int area_number;
srand(time(NULL));
area *area_array[AREASIZE] = {};
create_areas(area_array);
printf("Hello");
return 0;
}
void create_areas(area *area_array[NAREA])
{
printf("create areas\n");
for (int i = 0; i < AREASIZE; i++)
{
printf("First for loop\n");
for (int j = 0; j < NAREA; j++)
{
printf("Second for loop\n");
area_array[i]->subarea_array[j]->co2_cost = 0;
printf("Second for loop\n");
area_array[i]->subarea_array[j]->time = 0;
printf("Second for loop\n");
area_array[i]->subarea_array[j]->average = 0;
printf("Second for loop\n");
sensor_data_start(area_array[i], 0);
}
area_array[i]->average = 0;
}
}
void sensor_data_start(area *area, double start_var)
{
for (int i = 0; i < NAREA; i++)
{
for (int j = 0; j < SIZE; j++)
{
area->subarea_array[i]->sensorData[j] = start_var;
}
}
}
This:
area *area_array[AREASIZE] = {};
Creates an array of pointers to areas (area *). You have yet to create any areas!.
Thus when you try to access area_array[i]->subarea_array you access unallocated memory, causing a crash.
Look into pointers in C if you don't understand why.
Look into the malloc and free functions to actually instantiate your areas. You will also need the sizeof operator.
Note: you will have to do the same with subareas.
In the end you're looking for something like this:
void create_areas(area *area_array[NAREA])
{
printf("create areas\n");
for (int i = 0; i < AREASIZE; i++)
{
area_array[i] = malloc(sizeof(area)); //or malloc(sizeof(*area_array[i]))
if (area_array[i] == NULL) //always check malloc return value!!
exit(-1);
printf("First for loop\n");
for (int j = 0; j < NAREA; j++)
{
area_array[i]->subarea_array[j] = malloc(sizeof(subarea));
if (area_array[i]->subarea_array[j] == NULL) //always check malloc return value!!
exit(-1);
printf("Second for loop\n");
area_array[i]->subarea_array[j]->co2_cost = 0;
printf("Second for loop\n");
area_array[i]->subarea_array[j]->time = 0;
printf("Second for loop\n");
area_array[i]->subarea_array[j]->average = 0;
printf("Second for loop\n");
sensor_data_start(area_array[i], 0);
}
area_array[i]->average = 0;
}
}
Happy Learning!
Use pointer to structs which will act as array :
typedef struct subarea
{
int co2_cost, time;
double average, sensorData[SIZE];
// note that you can also define sensorSata as pointer and allocate dynamically
} subarea;
typedef struct area
{
subarea *subarea_array; // will be allocated dynamically
double average;
} area;
int main(void)
{
…
/*allocate soace for the area array */
area *area_array = calloc(AREASIZE, sizeof(area));
create_areas(area_array);
printf("Hello");
return 0;
}
void create_areas(area *area_array)
{
printf("create areas\n");
for (int i = 0; i < AREASIZE; i++)
{
/* allocate space for subarea */
area_array[i].subarea_array = malloc(sizeof(subarea)*NAREA);
printf("First for loop\n");
for (int j = 0; j < NAREA; j++)
{
printf("Second for loop\n");
area_array[i].subarea_array[j].co2_cost = 0;
printf("Second for loop\n");
area_array[i].subarea_array[j].time = 0;
printf("Second for loop\n");
area_array[i].subarea_array[j].average = 0;
printf("Sensor dafa start\n");
sensor_data_start(&area_array[i], 0);
}
area_array[i].average = 0;
}
}
void sensor_data_start(area *area, double start_var)
{
for (int i = 0; i < NAREA; i++)
{
// you can allocate sensorSata here if it was a pointer
for (int j = 0; j < SIZE; j++)
{
area->subarea_array[i].sensorData[j] = start_var;
}
}
}
Other things that could be done for more dynamic is to add the number of subarea in area struct if it is not constant . Same for sensorSata if you make it dynamic.
#include <stdio.h>
#include <stdlib.h>
struct arrayADT {
int *A;
int size;
int length;
int *B;
int arr3;
};
struct arrayADT * MergeArray(struct arrayADT *arr1, struct arrayADT *arr2) { //we create thus in heap cuz we need to be able to use these in main function
struct arrayADT *arr3 = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
int i, j, k;
i = j = k = 0;
while(i < arr1->length && j < arr1->length ) {
if(arr1->A[i] < arr2->A[j]) {
arr3->A[k] = arr1->A[i];
k++;
i++;
}
else {
arr3->A[k] = arr2->A[j];
k++;
j++;
}
}
for(; i<arr1->length ; i++) {
arr3->A[k] = arr1->A[i];
k++;
}
for(; j < arr2->length ; j++) {
arr3->A[k] = arr2->A[j];
k++;
}
arr3->length = arr1->length + arr2->length;
arr3->length = 10;
}
void main() {
struct arrayADT arr;
printf("Enter the size of an array");
scanf("%d", &arr.size);
arr.A = (struct arrayADT *)malloc(arr.size * sizeof(int));
arr.length = 0;
int n;
printf("enter the number of elements in an array");
scanf("%d", &n);
printf("enter the elements");
for(int i = 0; i < n; i++) {
scanf("%d", &arr.A[i]);
}
arr.length = n;
display(arr);
printf("Enter second array");
int j;
struct arrayADT *B = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
for(j = 0; j < arr.length; j++) {
scanf("%d", &B[j]);
}
struct arrayADT *arr3 = (struct arrayADT *)malloc(sizeof(struct arrayADT));
arr3 = MergeArray(&arr, &B);
display(*arr3);
I was looking to merge these arrays using heap memory and I am getting segmentation fault. I am new to C programming with pointers and I have been struck here it would be so helpful if I passed this barrier with your help.
And I am not getting where my error lies it would be helpful if someone specifies that too, so that I can avoid these errors in future.
PS: I am using minGW compiler.
In general, your code is rater unorganized. There are several cases for undefined behaviour, for example you don't scan in the second array correctly. The most probably candidate for your segmentaion fault is here:
struct arrayADT *arr3 = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
This will give you an uninitialized chunk of memory. The length and size could of arr3 be anything, and its data field A does not point to valid memory. Accessing it will likely crash.
You have three arrays in your code. You construct each step by step and you treat each differently. That leads to errors easily. Let's go about this more systematically.
Let's create a struct type for a fixed-size array: The maximum size must be given on creation and cannot change. The actual length of the array may be anything from 0 to its maximum size.
typedef struct Array Array;
struct Array {
int *value; // data array
int length; // actual length, 0 <= length <= size
int size; // maximum capacity
};
We create such arrays on the heap and because initializing the members is error-prone, we write a constructor:
Array *array_create(int size)
{
Array *array = calloc(1, sizeof(*array));
array->size = size;
array->value = calloc(size, sizeof(*array->value));
return array;
}
This function creates an empty array for at most size integers. If we allocate memory, we must de-allocate it later, so let's write a corresponding destructor function, which cleans up the ressources:
void array_destroy(Array *array)
{
if (array) {
free(array->value);
free(array);
}
}
After destroying an array, it can no longer be used, just as with memory after calling free() on it.
The array is at first empty, so let's write a function to add elements at its end if there is room:
void array_push(Array *array, int x)
{
if (array->length < array->size) {
array->value[array->length++] = x;
}
}
And a function to print it:
void array_print(const Array *array)
{
printf("[");
for (int i = 0; i < array->length; i++) {
if (i) printf(", ");
printf("%d", array->value[i]);
}
printf("]\n");
}
Now you can create arrays like so:
Array *a = array_create(10);
for (int i = 0; i < a->size; i++) {
array_push(a, i);
}
array_print(a);
array_destroy(a);
Your merge function will be simpler, too. Here's a full example. (But is uses generated array, not arrays typed in by the user.)
#include <stdio.h>
#include <stdlib.h>
typedef struct Array Array;
struct Array {
int *value;
int length;
int size;
};
Array *array_create(int size)
{
Array *array = calloc(1, sizeof(*array));
array->size = size;
array->value = calloc(size, sizeof(*array->value));
return array;
}
void array_destroy(Array *array)
{
if (array) {
free(array->value);
free(array);
}
}
void array_push(Array *array, int x)
{
if (array->length < array->size) {
array->value[array->length++] = x;
}
}
void array_print(const Array *array)
{
printf("[");
for (int i = 0; i < array->length; i++) {
if (i) printf(", ");
printf("%d", array->value[i]);
}
printf("]\n");
}
Array *merge(Array *a, Array *b)
{
Array *res = array_create(a->length + b->length);
int i = 0;
int j = 0;
while(i < a->length && j < b->length) {
if(a->value[i] < b->value[j]) {
array_push(res, a->value[i++]);
} else {
array_push(res, b->value[j++]);
}
}
while(i < a->length) {
array_push(res, a->value[i++]);
}
while(j < b->length) {
array_push(res, b->value[j++]);
}
return res;
}
int main(void)
{
Array *a = array_create(10);
Array *b = array_create(6);
Array *c;
for (int i = 0; i < a->size; i++) {
array_push(a, 1 + 3 * i);
}
for (int i = 0; i < b->size; i++) {
array_push(b, 4 + 2 * i);
}
array_print(a);
array_print(b);
c = merge(a, b);
array_print(c);
array_destroy(a);
array_destroy(b);
array_destroy(c);
return 0;
}
If you've read so far, here's the lowdown:
Organzie your code. That applies to code layout as much as writing small, generally applicable functions instead of doing everything "by hand". (The array type above is a bit on the fence: It uses functions, but getting at the data is still done via accessing the struct fields. You could even change the szie and length, whixh shouldn't really happen.)
Enable compiler warnings with -Wall. You will get useful information about potential (and often actual) errors.
Good luck!
i am trying to implement a linked-list in C with the aim to do a BFS on it.
The input for the list should look like this:
a-bc
b-a
c-a
which represents a list looking like this:
a
/ \
b c
now, my problem is that I cannot read the variable name defined in my Vertex struct. My program segfaults with Access Reading Violation. While printf("%s", s) takes a char *, casting the name to a char* doesn't help. The error takes place before the char is even accessed?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Vertex Vertex;
typedef struct Vertex
{
char name;
int visited;
int distance;
Vertex* next;
} Vertex;
struct Vertex* AddVertex(Vertex* head, char newVertexName)
{
Vertex* newHead = malloc(sizeof(Vertex));
newHead->name = newVertexName;
printf("added vertex named: %s", newHead->name); // causing the error
newHead->next = head;
newHead->visited = 0;
newHead->distance = 0;
return newHead;
}
int main()
{
// BFS
char s[100];
int l = 0;
const int nNrOfVerts = 27;
Vertex* adjList[28];
// initialise array of pointers
for(int i = 0; i <= nNrOfVerts; ++i)
{
adjList[i] = NULL;
}
// fill vertices with user data
for(int i = 1; i <= nNrOfVerts; ++i)
{
printf("enter %d vert: ", i);
if(scanf("%s", &s) != 1)
{
break;
}
l = strlen(s);
if(l > 2)
{
for(int k = 0; k < l; ++k)
{
// increment to accustom for the - seperator
if(1 == k)
{
k = 2;
}
adjList[i] = AddVertex(adjList[i], s[k]);
}
}
for(int k = 0; k < 100; ++k)
{
s[k] = NULL;
}
}
bfs(adjList);
// printing the list
for(int i = 1; i <= l; ++i)
{
for(int j = 0; j <= nNrOfVerts; ++j)
{
if(adjList[j]->distance == i)
{
printf("Level: %d is: %s", i, adjList[j]->name);
}
printf("No node for dist: %d", i);
}
}
return 0;
}
How can I access the value of newHead->name or adjList[i]->name for that matter? The interesting thing is, if I try to access adjList[i]->distance the correct integer is returned...
You declared name as a char but then you try to print it as a character :
printf("added vertex named: %s", newHead->name);
Change the %s to %c :
printf("added vertex named: %c", newHead->name);
or change your name to a char *.
I'm using a 2d-Array of pointers, each pointer points to a linked list of products.
I want to build a function that list all the products in all the lists.
This is my structure:
typedef struct object product, *pprod;
struct object{
int type;
int quantity;
pprod next;
};
This is how I'm defining the array (it has to be dynamic):
n=4;
m=3;
pprod (*t)[m] = malloc(n * sizeof *t);
list_all(t,n,m);
This is the function to show all the products:
void list_all(pprod** t , int size_n , int size_m) {
int i,j;
for(i=0;i<size_n;i++){
printf("--- Corridor ---: %d\n", i);
for(j=0;j<size_m;j++){
printf("--- Shelf ---: %d\n",j);
printf("product:%d quantity:%d",t[i][j]->type,t[i][j]->quantity);
}
}
}
I'm having troubles passing the array as a parameter. Can you help me find the problem?
Thanks for the help.
Well, first the creation of the array is wrong. You are just assigning one (single) vector of size 4 to the m+1 th element (the t vector, unless you do it elsewhere, points to random-land).
n=4;
m=3;
product **t, *newitem;
t= (product **)calloc(n, sizeof(product *)); // array of n pointers (corridor)
for (int i= 0; i<n; i++) {
t[i]= (product *)calloc(m, sizeof(product)) // array of m prod structs (m shelfs per corridor)
}
// access some array members (t[n][m] max t[0-2][0-3])
t[0][0].type= 0;
t[0][0].quantity= 0;
t[0][1].type= 1;
t[0][1].quantity= 11;
...
t[1][2].type= 12;
t[1][2].quantity= 1212;
....
t[2][3].type= 23;
t[2][3].quantity= 2323;
// more products could be linked to the existing ones
newitem= calloc(1, sizeof product);
newitem->type= 231;
newitem->quantity= 231231;
t[2][3].next= newitem;
// now list them via below function
list_all(t,n,m);
....
void list_all(product **t , int size_n , int size_m)
{
int i,j;
product *p;
for(i=0;i<size_n;i++){
printf("--- Corridor ---: %d\n", i);
for(j=0;j<size_m;j++){
printf("--- Shelf ---: %d\n",j);
p= &t[i][j];
do {
printf("product:%d quantity:%d", p->type, p->quantity);
p= p->next;
} (while p!=NULL);
}
}
}
See also my comment at Etienne's answer for more details.
From your problem description you want to represent i corridors * j shelfs * k products, where each product has a quantity and a type.
In your question you said you want to use a 2D array of pointers but your function list_all takes a 3D array as first argument (t is of type object***). Furthermore your structure object is meant to be a linked list node since it has a next member, but you use it like an array, for example with t[i][j]->quantity, which can not work and attempts to access unallocated memory.
To help reducing this kind of confusion name your variable more explicitly and avoid one letter variable names (n,m,t in your problem) except for loop iterators. Your program will be easier to read and those problems will appear more easily.
Here is a working solution to your problem using a 3D array:
#include <stdio.h>
#include <stdlib.h>
typedef struct object prod;
struct object {
int type;
int quantity;
};
void list_all(prod ***shop, int nb_corridors , int nb_shelfs, int nb_prods)
{
int i,j,k;
for (i = 0; i < nb_corridors; i++) {
printf ("--- Corridor ---: %d\n", i);
for (j = 0; j < nb_shelfs; j++) {
printf ("--- Shelf ---: %d\n", j);
for (k = 0; k < nb_prods; k++) {
printf ("--- Product ---: %d\n", k);
printf ("type:%d quantity:%d\n",
shop[i][j][k].type, shop[i][j][k].quantity);
}
}
}
}
int main(void)
{
int nb_corridors = 4;
int nb_shelfs = 5;
int nb_prods = 3;
prod ***shop;
// array of n pointers (corridor)
shop = malloc(nb_corridors * sizeof(*shop));
printf("sizeof(*shop)=%ld\n", sizeof(*shop));
int i, j;
for (i = 0; i < nb_corridors; i++) {
// nb_shelfs shelfs per corridor)
shop[i] = malloc(nb_shelfs * sizeof(*shop[i]));
printf("sizeof(*shop[i])=%ld\n", sizeof(*shop[i]));
for(j = 0; j < nb_shelfs; j++) {
shop[i][j] = malloc(nb_prods * sizeof(*shop[i][j]));
printf("sizeof(*shop[i][j])=%ld\n", sizeof(*shop[i][j]));
}
}
//initialize with dummy values
int k;
for(i = 0; i < nb_corridors; i++) {
for(j = 0; j < nb_shelfs; j++) {
for(k = 0; k < nb_prods; k++) {
shop[i][j][k].type = k;
shop[i][j][k].quantity;
}
}
}
list_all(shop, nb_corridors, nb_shelfs, nb_prods);
return 0;
}
pprod is already a pointer, I believe the problem is how you pass the parameters to the function.
try changing to this function prototype:
t is already a pointer to a pointer and you aren't changing it anyhow..
void list_all(pprod* t , int size_n , int size_m) {
I've played with Graphs before and I managed it alright with some help from StackOverflow but I never used a structure like the one below. I can't seem to understand what I'm doing wrong here...
#include "stdio.h"
#include "stdlib.h"
#define MaxV 100
#define MaxE 50
typedef struct edge {
int dest;
int cost;
struct edge *next;
} Edge, *Graph[MaxV];
Graph *initGraph() {
Graph *g = (Graph*)malloc(sizeof(Edge) * MaxV);
for(int i = 0; i < MaxV; i++)
(*g[i])->next = NULL;
return g;
}
int main(void) {
Graph *g = initGraph();
for(int i = 0; i < MaxV; i++) {
if((*g[i])->next == NULL) printf("[%02d] NULL\n", i);
}
return 0;
}
I get a segmentation fault on the first iteration of (*g[i])->next = NULL; and I can't understand why. I've tried countless things but I can't seem to manage the Graph initialization with such structure. Also, is the way I'm declaring and returning a pointer to a Graph done the right way for this structure?
Am I complicating things with lots of pointers in the init function or what?
P.S: Please do not suggest different structure definitions, I cannot changing anything in the one above. That's the real issue. I know how to work with Graphs rolling my own structure, but I need to use the one above.
I don't really understand your second typedef of *Graph[MaxV].
What I would do is declare another struct as follows:
typedef struct graph {
Edge *edges;
} Graph;
Then you can initialize the graph as follows:
Graph *initGraph() {
Graph *g = (Graph*)malloc(sizeof(Graph));
g->edges = (Edge*)malloc(sizeof(Edge) * MaxV);
for(int i = 0; i < MaxV; i++)
g->edges[i].next = NULL;
return g;
}
And printing out the graph is as follows:
for(int i = 0; i < MaxV; i++) {
if(g->edges[i].next == NULL) printf("[%02d] NULL\n", i);
}
I think you'll find that having an extra struct for the graph will prove to be more sustainable over time too. :)
Complete revision of answer given the OP's requirement not to change the typedef in any way.
I would advise changing to this:
void initGraph(Graph g) {
g[0] = malloc(sizeof(Edge) * MaxV);
for(int i = 0; i < MaxV; i++)
g[0][i].next = NULL;
return;
}
int main(void) {
Graph g;
initGraph(g);
for(int i = 0; i < MaxV; i++) {
if(g[0][i].next == NULL) printf("[%02d] NULL\n", i);
}
free(g[0]);
return 0;
}
The problem here is the "array of pointers" syndrome. Namely Graph** g is equivalent to Graph *g[10] with the obvious proviso that the outer array size is fixed. That creates problems because you can't return a fixed size array, but you can return a **.
I'm still not sure what the use case for an array of graphs is, but heck, this passes valgrind.
I think I found the solution I was looking for. I used Valgrind as best as I could to test for read/write permissions and there were no errors. Yes there were memory leaks, but that's not the point of this question (I'm aware of those, don't worry).
Here's the whole code to create a simple graph. Would love to hear any problems this implementation might have...
#include "stdio.h"
#include "stdlib.h"
#define MaxV 10
#define MaxE 5
typedef struct edge {
int dest;
int cost;
struct edge *next;
} Edge, *Graph[MaxV];
Graph *initGraph() {
Graph *g = (Graph*)malloc(sizeof(Graph));
for(int i = 0; i < MaxV; i++)
(*g)[i] = NULL;
return g;
}
int insertEdge(Graph *g, int o, int d, int c) {
if(!g) return -1;
Edge *edge = (Edge*)malloc(sizeof(Edge));
edge->dest = d;
edge->cost = c;
edge->next = (*g)[o];
(*g)[o] = edge;
return 0;
}
int main(void) {
Graph *g1 = initGraph();
Edge *aux = NULL;
insertEdge(g1, 0, 1, 2);
insertEdge(g1, 0, 2, 3);
insertEdge(g1, 1, 4, 5);
insertEdge(g1, 2, 4, 1);
insertEdge(g1, 4, 8, 6);
for(int i = 0; i < MaxV; i++) {
printf("[%02d]\n", i);
for(aux = (*g1)[i]; aux != NULL; aux = aux->next)
printf(" [%d] » [%d] (%d)\n", i, aux->dest, aux->cost);
}
return 0;
}