why I am getting segmentation fault with scanf at large inputs - c

I have written c code to merge sort a array of input
and I tried the code for 2 3 5 10 100 1000 10,000 and 1,000,000
it worked as desired in all cases except the 10,000 and 1,000,000
after debugging I found that the error is within scanf() code
Program received signal SIGSEGV, Segmentation fault.
0x00000000004006a7 in main () at merge.c:10
10 scanf("%i",&array[i]);
but the code is perfectly correct as far as I am concerned
int len;
scanf("%i",&len);
int array[len];
for(int i=0; i<len;i++)
{
scanf("%i",&array[i]);
}
In case you need the full code for clearification here it is
#include <stdio.h>
void mergesort(int* list , int len);
int main()
{
int len;
scanf("%i",&len);
int array[len];
for(int i=0; i<len;i++)
{
scanf("%i",&array[i]);
}
mergesort(array,len);
for(int i=0; i<len;i++) printf("%i\n",array[i]);
printf("\b");
}
void mergesort (int* list, int len)
{
if(len == 1) return;
int i = len/2, j = len-i;
int list1[i], list2[j];
for(int k=0;k<i;k++)
{
list1[k]= list[k];
list2[k]= list[i+k];
}
if(len%2!=0) list2[j-1] = list[len-1];
mergesort(list1 , i);
mergesort(list2 , j);
int k=0,l=0;
// k represent counter over elements in list1
// l represent counter over elements in list2
// k+l represent counte over total elements in list
while(k+l!=len)
{
if(k==i)
{
for(;l<j;l++) list[k+l] = list2[l];
return;
}
else if (l==j)
{
for(;k<i;k++) list[k+l] = list1[k];
}
else if(list1[k]<list2[l])
{
list[k+l]=list1[k];
k++;
}
else if(list1[k]>list2[l])
{
list[k+l] = list2[l];
l++;
}
else
{
//handles dublication
list[k+l] = list1[k];
k++;
list[k+l] = list[l];
l++;
}
}
}
EDIT:
in case you believe that the problem platform dependent I use ubuntu 14.04
and gnu c compiler 4.8.2 and I compile the code with flags -std=c99 -Wall
and it is error and warning free

Merge sort eats plenty of memory, and you're allocating additional memory in what c programmers call stack ( int list1[i], list2[j]; ). And there's actually little room in stack. Doing it over and over again for large values exceeds the limit.
You must use heap allocations instead - dynamic allocations. Heap has plenty of memory available for allocation and is used for large arrays among other purposes. You do it like this:
//C example with malloc, ALWAYS use sizeof
int *array = (int*) malloc( length * sizeof(int));
//C++ way
int *array = new int[length];
But memory remains allocated after the program ends, unless you free it. Which can be a problem in thid case. Make sure to unallocate it when you no longer need it.
//C way
free(array);
//C++ way for arrays
delete[] array;
//C++ way for single heap values
delete value;
This is the right way so you should get used to it as youll need dynamic allocation very much in future.

Related

A function in C runs for a set of values but gives Segmentation Fault: 11 for another

I am trying to find unique non-zero intersection between two sets. I have written a program which works for some set of arrays but gives segmentation fault for some. I have been trying to figure out why but have failed, any help will be greatly valued. The thing is the functions defined (NoRep and ComEle) are working fine but are unable to return the value to the assigned pointer in the case when Seg Fault is shown. Below is the code:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
int* ComEle(int ar_1[], int size_ar1, int ar_2[], int size_ar2);
int* NoRep(int a[], int l1);
int main ()
{
// Case 1: Gives segmentation fault
int A[10] = {1,1,0,2,2,0,1,1,1,0};
int B[10] = {1,1,1,1,0,1,1,0,4,0};
int *C = ComEle(A,10,B,10); printf("check complete\n");
// //Case 2: Does not give segmentation fault
// int A[4] = {2,3,4,5};
// int B[4] = {1,2,3,4};
// int *C = ComEle(A,4,B,4); printf("check complete\n");
}
//---------------- Local Functions --------------------//
int* ComEle(int ar_1[], int size_ar1, int ar_2[], int size_ar2) {
// sort of intersection of two arrays but only for nonzero elements.
int i=0, j=0, cnt1 = 0;
int temp1 = size_ar1+size_ar2;
int CE1[temp1]; for(i=0;i<temp1;i++) {CE1[i] = 0;}
/* Size of CE1 is knowingly made big enough to accommodate repeating
common elements which can expand the size of resultant array to
values bigger than those for the individual arrays themselves! */
for(i=0;i<size_ar1;i++) {
j = 0;
while(j<size_ar2) {
if(ar_1[i]==ar_2[j] && ar_1[i]!=0) {
CE1[cnt1] = ar_1[i];
cnt1++;
}
j++;
}
}
// Have to remove repeating elements.
int *CE = NoRep(CE1, cnt1);
for(i=0;i<(CE[0]+1);i++) {printf("CE:\t%d\n", CE[i]);}
printf("ComEle: %p\n",CE);
return(CE);
}
int* NoRep(int a[], int l1) {
int cnt = 0, i = 0, j =0;
int *NR; NR = (int*)calloc((l1), sizeof(int));
//int NR[l1]; for(i=0;i<l1;i++) {NR[i] = 0;}
for(i=0;i<l1;i++) {
j = 0;
while(j<i) {
if(a[i]==a[j]) {break;}
j++;
}
if(j == i) {
cnt++;
NR[cnt] = a[i];
}
}
NR[0] = cnt; // First element: # of relevant elements.
printf("NoRep: %p\n",NR);
return(NR);
}
Thanks again for your help!
Take a look at this code:
int temp1 = size_ar1+size_ar2;
int CE1[temp1]; for(i=0;i<temp1;i++) {CE1[i] = 0;}
/* Size of CE1 is knowingly made big enough to accommodate repeating
common elements which can expand the size of resultant array to
values bigger than those for the individual arrays themselves! */
for(i=0;i<size_ar1;i++) {
j = 0;
while(j<size_ar2) {
if(ar_1[i]==ar_2[j] && ar_1[i]!=0) {
CE1[cnt1] = ar_1[i];
cnt1++;
}
j++;
}
}
Here you have nested loops, i.e. a for-loop with a while-loop inside. So - in worst case - how many times can cnt1 be incremented?
The answer is size_ar1 * size_ar2
But your code only reserve size_ar1 + size_ar2 element for CE1. So you may end up writing outside the array.
You can see this very easy by printing cnt1 inside the loop.
In other words - your CE1 is too small. It should be:
int temp1 = size_ar1*size_ar2; // NOTICE: * instead of +
int CE1[temp1]; for(i=0;i<temp1;i++) {CE1[i] = 0;}
But be careful here - if the input arrays are big, the VLA gets huge and you may run in to stack overflow. Consider dynamic memory allocation instead of an array.
Besides the accepted answer: I have been missing a break statement in the while loop in ComEle function. It was not giving me the expected value of cnt1. The following will be the correct way to do it:
for(i=0;i<size_ar1;i++) {
j = 0;
while(j<size_ar2) {
if(ar_1[i]==ar_2[j] && ar_1[i]!=0) {
CE1[cnt1] = ar_1[i];
cnt1++;
break;
}
j++;
}
}
This will also do away with the requirement for a bigger array or dynamic allocation as suggested (and rightly so) by #4386427

How to fix a segmentation error (core dumped) within a function using structs

Trying to initialize a function so its data members are 0 for the numerical values and "none" for the string but a segmentation error occurs for the strcpy.
This is for a code that creates a 2d array of an island of x,y points and prior to the later functionality I need to initialize the function to default (0's and none). I have tried to mess with the pointers and not using strcpy but to my understanding for updating strings, strcpy is needed.
typedef struct Hill {
char name[20];
int loc[2];
double height;
double slope;
} Hill;
Hill* setHill (Hill* hill){
strcpy(hill->name, "none"); // error appears to be here
hill->loc[0] = 0;
hill->loc[1] = 0;
hill->height = 0;
hill->slope = 0;
return hill;
}
int main() {
Hill* hillsArray[5];
int i;
// calling setHill to populate an array of 5 hills
for(i=0; i<5; ++i) {
setHill(hillsArray[i]);
}
// updating hill "ada's apex"
strcpy((hillsArray[0]->name), "Ada's Apex");
hillsArray[0]->loc[0] = 12;
hillsArray[0]->loc[1] = 9;
hillsArray[0]->height = 20;
hillsArray[0]->slope = 0.25;
// updating hill turing's top
strcpy((hillsArray[1]->name), "Turing's top");
hillsArray[1]->loc[0] = 4;
hillsArray[1]->loc[1] = 3;
hillsArray[1]->height = 20;
hillsArray[1]->slope = 0.33;
This updating of the hill repeats 3 more times for a total of 5 hills but its the same code just updating each hill with different values.
At least one problem, you're not allocating any memory for the Hills. Hill* hillsArray[5]; is an array of Hill pointers. They point to nowhere, so when you do hill->name, you're dereferencing a bad pointer, which is undefined behavior, which in your case is manifesting itself as a seg fault. You need to allocate memory for each Hill object, either dynamically or automatically, like this:
// dynamically (following what you have now)
int main() {
Hill* hillsArray[5];
int i;
// calling setHill to populate an array of 5 hills
for(i=0; i<5; ++i) {
hillsArray[i] = malloc(sizeof(hillsArray[0])); // equivalent to malloc(sizeof(struct Hill));
if (hillsArray[i] == NULL)
{
// in the case the malloc fails, handle the error however you want
printf("Could not allocate memory for Hill %d\n", i);
return 1;
}
setHill(hillsArray[i]);
}
....
// it's considered good practice to clean up memory you dynamically allocate,
// although you will find differing opinions of that on SO, so up to you.
// When your process exits, the OS will clean up any allocated memory, so
// in this case, it's not all that important to clean it up yourself. But
// for programs that run indefinitely, it's much more of a concern.
for (i=0; i<5; i++)
{
free(hillsArray[i]);
}
}
Or if you don't want to mess with dynamically allocating memory (I don't unless I have to), you can
// setup Hills in automatic storage instead
int main() {
Hill hillsArray[5]; // each hill is in automatic storage, probably on the stack
int i;
// calling setHill to populate an array of 5 hills
for(i=0; i<5; ++i) {
setHill(&(hillsArray[i])); // now you must pass the address of each Hill to the setHill function
}
....
// since it's automatic storage, no need to clean it up yourself
}

Game of Life pointers

I am creating game of Life in C and I am getting this segmentation fault (core dumped) error after the program takes input from user. I recently started learning C and my understanding of pointers is basic .I have not been able to find a fix for it after looking online and trying different ways to get it right. If i dont use pointers and keep it simple everything works right.I would appreciate any help
int main() {
int maxR;
int maxC;
int generations;
int i=0;
int j=0;
int k=0;
int n; //neighbour count
char state;
char **board; //original boardfor comparison
char **newBoard; //boardto make changes to
scanf("%d %d %d",&maxR,&maxC,&generations); //take input
board= (char**)malloc(maxR * sizeof(char*)); //allocating memory
newBoard=(char**) malloc(maxR * sizeof(char*)); //allocating memory
for(i=0; i<maxR; i++) {
board[i] = malloc(maxC * sizeof (char)); //allocating memory
newBoard[i] = malloc(maxC * sizeof (char)); //allocating memory
for(j=0; j<maxC; j++) {
scanf (" %c", &board[i][j]); //getting input
}
}
for(i=0; i<=generations; i++ ) {
for (j=0; j<maxR; j++) {
for (k=0; k<maxC; k++) {
state=board[j][k];
n=countNeighbours(board,maxR,maxC,j,k);
if(state == '1') { //if the cell is alive
if(n==2 || n==3) newBoard[j][k] = '1'; //if the cell has 2 or 3 neighbours then it lives
else newBoard[j][k]='0'; //else the cell dies
} else { //else (if) the cell is dead
if(n==3) newBoard[j][k]='1'; //but has 3 neibours then the cell become alive
else newBoard[i][j]='0'; //else it dies
}
}
}
memcpy(board, newBoard,sizeof(board)); //copy the updated grid to the old one
}
printBoard(board,maxR,maxC);
deallocate(board,maxR); //deallocatethe memory
deallocate(copyGrid,maxR); //deallocatethe memory
There's one obvious problem here.
memcpy(oldGrid, copyGrid,sizeof(oldGrid)); //copy the updated grid to the old one
As oldGrid is a char** pointer, then sizeof(oldGrid) is the size of a pointer, which is probably 4 or 8 bytes depending on your platform. So, you're not copying the grid, you're only copying a few bytes of it.
If you want to copy the whole grid, you need to work out the size of the grid in bytes.
If oldGrid was declared as an array, instead of a pointer, then sizeof(oldGrid) would yield the full size of the grid as you expect. Arrays behave differently from pointers when it comes to sizeof().

C segmentation fault

I'm trying to create a sub array with the following function :
Track * subArray(Track * arr, int start, int end){
int size = end - start;
Track * t = malloc(sizeof(Track) * size);
for(int i = 0; i < size && start <= end; i++){
t[i] = arr[start++];
}
}
The size of the t pointer is always 8, even when I don't multiply it with size and I get a segmentation fault. I'm new to C so I don't know what is causing this exception.
This is why C is hard. It's an off by one error: You need to allocate (end-start+1) items and use <= in the loop. Try rewriting to something like this:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Track {
char* color;
} Track;
Track * subArray(Track* arr, int start, int end){
assert(end > start);
const int size = 1 + end - start;
printf("Allocating %d items\n", size);
Track* t = malloc(sizeof(Track)*size);
for(int i=start; i <= end; ++i) {
printf("at %d fetching %d\n", i-start, i);
t[i-start] = arr[i];
}
return t;
}
int main() {
Track *track = malloc(sizeof(Track) * 7);
track[0].color = "red";
track[1].color = "orange";
track[2].color = "yellow";
track[3].color = "blue";
track[4].color = "indigo";
track[5].color = "green";
track[6].color = "violet";
Track *sub = subArray(track, 3, 5);
printf("%s\n", sub[0].color);
printf("%s\n", sub[1].color);
printf("%s\n", sub[2].color);
}
Compiling and running:
$ cc -g -W -Wall a.c && ./a.out
Allocating 3 items
at 0 fetching 3
at 1 fetching 4
at 2 fetching 5
blue
indigo
green
Note that I'm copying the value of char* pointers here. That may lead to additional confusing stuff, just in case you think about copying my code (I just drafted something that works to illustrate the problem).
Update
You're using inclusive indices. In C, however, it's quite common to specify a start index and a length. A lot of standard library functions do this, and this is what you'll most likely see in production code. One reason may be that it's easier to reason with. In your case, the code would be
Track* subArray(Track* arr, const size_t start, const size_t length) {
Track* t = malloc(sizeof(Track) * length);
for (size_t i = 0; i < length; ++i)
t[i] = arr[i + start];
return t;
}
and the corresponding call would be
Track *sub = subArray(track, 3, 3);
In my eyes, this not only looks better; it's simpler and easier to understand.
Another thing that's common is to copy pointers instead of the whole structs. This will depend on how your code and data structures are organized. In that case, it's quite common to use a sentry value at the end of an array of pointers to mark its end: This will typically be a NULL pointer.
Keep practising and keep reading other people's code, and you'll soon discover C idioms and programming styles that will make your life much easier!
I think your error is that you're using <= in your tests when they should be <. This will prevent you from running off the end of your arrays.

Struct Array initialization in c

typedef struct _set{
int root;
int rank;
}Set;
void Kruskal(Graph* g)
{
Set uni[g->nv];
Edge result[g->nv - 1];
int i;
int count = 0;
int num = 0;
int aRoot, bRoot;
for(i = 0; i < g->nv; i++){
uni[i].root = i;
uni[i].rank = 0;
}
QuickSort(g, 0, g->ne-1);
while(count != (g->nv-1) && num != g->ne){
WeightedUnion(uni, g->path[num].src, g->path[num].dest);
aRoot = Find(uni, g->path[num].src);
bRoot = Find(uni, g->path[num].dest);
if( aRoot != bRoot){
result[num] = g->path[num];
count++;
}
num++;
}
if(count != g->nv-1){
printf("No spanning tree\n");
}
else{
for(i = 0; i <= count; i++){
printf("[%d] %d - %d : %d\n",i+1,result[i].src,result[i].dest,result[i].weight);
}
}
}
This is my part of code. The problem is that I can't initialize 'uni[g->nv]'. You can see 'for' loop next to the variable area. And I was sure about that reputation must initialize this array but a result was not. That array didn't include any other values. just empty. I cannot find my problem. Please tell me my problem or mistakes.
I run my code in Xcode. Maybe this information is helpful
You are using a variable length array (VLA), that is an array with a length that depends dynamically on an expression during run time. Since the size is not known at compile time, you can't initialize them with an initializer expression, but must do it with a for loop as you are doing.
VLA are usually realized when your program executes on the so-called stack of the function in which it is defined. That stack has a size limit and you have to be careful that you don't overrun it. (And if you do, there is no tool to know directly.)
So don't use VLA as you do for big data of unknown size. Instead, use a pointer and malloc to allocate the memory that you need.

Resources