SIGSEGV in C error - c

I always get an SIGSEGV error whenever i am dynamically initializing arrays in C. Please tell me what am I doing wrong all the time?
The code works fine on TurboC but it gives SIGSEGV on an online judge which uses GCC.
Programming Problem
My code:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
long n,h,i,crane=0,box=0,temp=0;
long *comm;
scanf("%ld %ld",&n,&h);
long *a = (long*)malloc(n*sizeof(long));
for(i=0;i<n;i++)
scanf("%ld",&a[i]);
scanf("%ld",&comm[0]);
i=0;
while(comm[i]!=0)
{
i++;
scanf("%ld",&comm[i]);
}
for(i=0;comm[i]!=0;i++)
{
if(comm[i]==3)
box=1;
if(comm[i]==4 && box==1)
{
a[crane]=(a[crane]+1);
temp=0;
}
if(box==1 && (comm[i]==1 || comm[i]==2) && temp==0)
{
a[crane]=(a[crane]-1);
temp=1;
}
if(crane!=0 && comm[i]==1)
crane--;
if(comm[i]==2)
crane++;
if(comm[i]==0)
break;
}
for(i=0;i<n;i++)
printf("%ld ",a[i]);
free(a);
free(comm);
return 0;
}

For a start, nowhere in that code are you actually allocating memory for comm to point to. You apparently know this is required since you've done something similar for a and you free both a and comm at the end.
You need to malloc the memory for comm to point to, before using it. For example, if you wanted that to depend on the second value input (h, probable since it's not used anywhere else), you would need to add in:
comm = malloc(h*sizeof(long));
after the first scanf, noting that I don't cast the return value - you shouldn't do that in C.
If you don't know how big comm should be before using it, the usual way to handle that is to allocate a certain number of elements (the capacity) and keep track of how many you've used (the size). Each time when your size is about to exceed your capacity, use realloc to get more space.
The following (C-like) pseudo-code shows how to do this, starting with an empty array and expanding it by thirty elements each time more space is needed:
comm = NULL
capacity = 0
size = 0
for each value in input():
if size == capacity:
capacity += 30
comm = realloc (comm, capacity), exit if error
comm[size++] = value
Note that, on loop exit, size is the indicator of how many elements are in the array, despite the fact there may be more capacity.
And, as an aside, you should always assume that calls subject to failure (such as scanf and malloc) will fail at some point. In other words, check the return values.

Related

Limit for memory allocation to an array on stack in C?

I don't know how to ask this question as it was little confusing to me. i was having a problem with this code
#include <stdio.h>
#include <stdlib.h>
#define ull unsigned long long
#define SIZE 1000000001
#define min(a,b) ((a<b?a:b))
#define max(a,b) ((a>b?a:b))
int solve(void) {
// unsigned *count = malloc(sizeof(unsigned) * SIZE);
int k;
scanf("%d", &k);
unsigned count[SIZE];
for (ull i = 0; i < SIZE; i++){
count[i] = 0;
}
return 0;
}
int main(void){
unsigned t;
if (scanf("%u", &t) != 1) return 1;
while (t-- > 0){
if (solve() != 0) return 1;
}
}
This code for me is giving segfault.
What my observation is
it is running fine until it is in solve function.
on calling solve function it is giving segfault.
It has nothing to do with scanf("%d", &k) as by removing this line gives the same error
But if we decrease the SIZE value it will run fine.
Other thing which i can do is instead of creating an array on stack i can use heap and this is working fine.
If i only declare array count in solve function instead of taking k as input and initializing all the values of array count to 0. i am not getting any segfault
So i have some questions regarding this.
Is this due to memory limitation to array or because of memory limitation for a stack frame for the function solve (or possibly another reason which i can't find).
If this is due to any kind of memory limitation than isn't it is too low for a program?
How compiler checks for such errors as adding any kind of print statement won't run before array declaration as i am getting segfault when program reaches solve. So compiler somehow knows that their is a problem with code without even getting there.
and specifically for the 6th point, as per my knowledge when declaring array it reserves memory for the array. So by initializing it i am doing nothing which will increase the size of array. So why i am not getting any kind of error when declaring array while i am getting segfault when i am initializing all those values in array
Maybe i am seeing it in totally wrong way but this is how i think it is, So please if you know any reason for this please answer me about that too
It depends on your operating system. On Windows, the typical maximum size for a stack is 1MB, whereas it is 8MB on a typical modern Linux, although those values are adjustable in various ways.
For me it's working properly check with other platform or other system.

Do arrays in C have a maximum index size of 2048?

I've written a piece of code that uses a static array of size 3000.
Ordinarily, I would just use a for loop to scan in 3000 values, but it appears that I can only ever scan in a maximum of 2048 numbers. To me that seems like an issue with memory allocation, but I'm not sure.
The problem arises because I do not want a user to input the amount of numbers they intend to input. They should only input whatever amount of numbers they want, terminate the scan by inputting 0, after which the program does its work. (Otherwise I would just use malloc.)
The code is a fairly simple number occurrence counter, found below:
int main(int argc, char **argv)
{
int c;
int d;
int j = 0;
int temp;
int array[3000];
int i;
// scanning in elements to array (have just used 3000 because no explicit value for the length of the sequence is included)
for (i = 0; i < 3000; i++)
{
scanf("%d", &array[i]);
if (array[i] == 0)
{
break;
}
}
// sorting
for(c = 0; c < i-1; c++) {
for(d = 0; d < i-c-1; d++) {
if(array[d] > array[d+1]) {
temp = array[d]; // swaps
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
int arrayLength = i + 1; // saving current 'i' value to use as 'n' value before reset
for(i = 0; i < arrayLength; i = j)
{
int numToCount = array[i];
int occurrence = 1; // if a number has been found the occurence is at least 1
for(j = i+1; j < arrayLength; j++) // new loops starts at current position in array +1 to check for duplicates
{
if(array[j] != numToCount) // prints immediately after finding out how many occurences there are, else adds another
{
printf("%d: %d\n", numToCount, occurrence);
break; // this break keeps 'j' at whatever value is NOT the numToCount, thus making the 'i = j' iterator restart the process at the right number
} else {
occurrence++;
}
}
}
return 0;
}
This code works perfectly for any number of inputs below 2048. An example of it not working would be inputting: 1000 1s, 1000 2s, and 1000 3s, after which the program would output:
1: 1000
2: 1000
3: 48
My question is whether there is any way to fix this so that the program will output the right amount of occurrences.
To answer your title question: The size of an array in C is limited (in theory) only by the maximum value that can be represented by a size_t variable. This is typically a 32- or 64-bit unsigned integer, so you can have (for the 32-bit case) over 4 billion elements (or much, much more in 64-bit systems).
However, what you are probably encountering in your code is a limit on the memory available to the program, where the line int array[3000]; declares an automatic variable. Space for these is generally allocated on the stack - which is a chunk of memory of limited size made available when the function (or main) is called. This memory has limited size and, in your case (assuming 32-bit, 4-byte integers), you are taking 12,000 bytes from the stack, which may cause problems.
There are two (maybe more?) ways to fix the problem. First, you could declared the array static - this would make the compiler pre-allocate the memory, so it would not need to be taken from the stack at run-time:
static int array[3000];
A second, probably better, approach would be to call malloc to allocate memory for the array; this assigns memory from the heap - which has (on almost all systems) considerably more space than the stack. It is often limited only by the available virtual memory of the operating system (many gigabytes on most modern PCs):
int *array = malloc(3000 * sizeof(int));
Also, the advantage of using malloc is that if, for some reason, there isn't enough memory available, the function will return NULL, and you can test for this.
You can access the elements of the array in the same way, using array[i] for example. Of course, you should be sure to release the memory when you've done with it, at the end of your function:
free(array);
(This will be done automatically in your case, when the program exits, but it's good coding style to get used to doing it explicitly!)

Bus Error in C for Loop

I have a toy cipher program which is encountering a bus error when given a very long key (I'm using 961168601842738797 to reproduce it), which perplexes me. When I commented out sections to isolate the error, I found it was being caused by this innocent-looking for loop in my Sieve of Eratosthenes.
unsigned long i;
int candidatePrimes[CANDIDATE_PRIMES];
// CANDIDATE_PRIMES is a macro which sets the length of the array to
// two less than the upper bound of the sieve. (2 being the first prime
// and the lower bound.)
for (i=0;i<CANDIDATE_PRIMES;i++)
{
printf("i: %d\n", i); // does not print; bus error occurs first
//candidatePrimes[i] = PRIME;
}
At times this has been a segmentation fault rather than a bus error.
Can anyone help me to understand what is happening and how I can fix it/avoid it in the future?
Thanks in advance!
PS
The full code is available here:
http://pastebin.com/GNEsg8eb
I would say your VLA is too large for your stack, leading to undefined behaviour.
Better to allocate the array dynamically:
int *candidatePrimes = malloc(CANDIDATE_PRIMES * sizeof(int));
And don't forget to free before returning.
If this is Eratosthenes Sieve, then the array is really just flags. It's wasteful to use int if it's just going to hold 0 or 1. At least use char (for speed), or condense to a bit array (for minimal storage).
The problem is that you're blowing the stack away.
unsigned long i;
int candidatePrimes[CANDIDATE_PRIMES];
If CANDIDATE_PRIMES is large, this alters the stack pointer by a massive amount. But it doesn't touch the memory, it just adjusts the stack pointer by a very large amount.
for (i=0;i<CANDIDATE_PRIMES;i++)
{
This adjusts "i" which is way back in the good area of the stack, and sets it to zero. Checks that it's < CANDIDATE_PRIMES, which it is, and so performs the first iteration.
printf("i: %d\n", i); // does not print; bus error occurs first
This attempts to put the parameters for "printf" onto the bottom of the stack. BOOM. Invalid memory location.
What value does CANDIDATE_PRIMES have?
And, do you actually want to store all the primes you're testing or only those that pass? What is the purpose of storing the values 0 thru CANDIDATE_PRIMES sequentially in an array???
If what you just wanted to store the primes, you should use a dynamic allocation and grow it as needed.
size_t g_numSlots = 0;
size_t g_numPrimes = 0;
unsigned long* g_primes = NULL;
void addPrime(unsigned long prime) {
unsigned long* newPrimes;
if (g_numPrimes >= g_numSlots) {
g_numSlots += 256;
newPrimes = realloc(g_primes, g_numSlots * sizeof(unsigned long));
if (newPrimes == NULL) {
die(gracefully);
}
g_primes = newPrimes;
}
g_primes[g_numPrimes++] = prime;
}

SIGSEGV error keeps showing up

this error keeps on appearing for every program i try to submit on spoj.pl
In the given code i need to find prime numbers between m - n for t no. of test cases .
problem statement:http://www.spoj.com/problems/PRIME1/
the same error is appearing ..
can anyone plss tell me why this error shows up again nd again ..
here's my code
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main()
{
int t;
scanf("%d",&t);
int *m,*n;
m=(int *)malloc(sizeof(int)*t);
n=(int *)malloc(sizeof(int)*t);
int i=0;
while(i<t)
{
scanf("%d%d",(m+i),(n+i));
i++;
}
i=0;
while(i<t)
{
long long int *list,j,k;
list=((long long int*)malloc(sizeof(long long int)*(n[i]+1)));
list[0]=list[1]=0;
for(j=2;j<=*(n+i);j++)
{
*(list+j)=1;
}
float l=sqrt(*(n+i)+1);
//int l=sqrt(*(n+i)+1);
for(j=2;j<=l;j++)
{
if(*(list+j)==1)
{
//printf("\n%ld",j);
for(k=j*j;k<=*(n+i);k=k+j)
*(list+k)=0;
}
}
for(j=m[i];j<=n[i];j++)
{
if(*(list+j)==1)
{
printf("\n%ld",j);
}
}
printf("\n");
free(list);
i++;
}
free(m);
free(n);
return 0;
}
First -- you should not cast malloc -- it can cause unexpected errors.
Second, there's no validation that you allocated the memory you need. There are three different places you're asking for memory and never look to see if malloc returned a NULL result... if t and/or (n[i]+1) is sufficiently large, malloc() may be unable to get a chunk of memory big enough to satisfy the request, in which case you're trying to assign to a NULL pointer and you get a SIGSEGV -- there's a hint given in the description of the problem
Warning: large Input/Output data, be careful with certain languages
(though most should be OK if the algorithm is well designed)
Seems to work fine on my computer, except for the warning about using %ld (%lld should be used). I can only obtain a SIGSEGV error when putting 0 as a value for n[i]. Could you indicate what values you used to generate that error?
Edit :
You are testing for the values "1 888888888 1000000000".
Your computer simply can't allocate an array of such size. You are asking an array of size 1000000001 in your memory. That amounts to about 8GB (since a long long int as about 8B, at least on my computer), which is pretty much undoable for your computer.

Segmentation fault when indexing into char array via pointer

My code is causing a segmentation fault when accessing an array element even though that element was already accessed without a problem.
int charToInt(char a)
{
int b;
if(isdigit(a))
{
b = a - '0' - 1;
}
if(isalpha(a))
{
b = a - 65;
}
return b;
}
int validPosition(char **array, int r, int c, char* position, int slots)
{
int i,k;
if(strlen(position) == 5)
{
if(!isalpha(position[0]) || !isdigit(position[1]) || position[2]!=' ' || (position[3]!='N' && position[3]!='E' && position[3]!='W' && position[3]!='S')) //lathos gramma
{
printf("\n%s", "Invalid answear.This is an example of a valid answear: A5 N");
return 2;
}
if( charToInt(position[0]) > r - 1 || charToInt(position[1]) > c - 1 )//ama vgainei eksw apo ta oria
{
printf("\n%s", "The position you choosed is out of the bountries...");
return 2;
}
printf("\n%s%c%s","position[3] is: ",position[3], " but it doesn't work >_<"); // position[3] is N
if(position[3] == 'N') //the problem is here <~~~~~~~~~~~~~~~~~~~<
{
printf("\n%s", "come on");
if(charToInt(position[0]) + slots < r)
{
for(i=charToInt(position[0])-1; i<charToInt(position[0])+slots; i++)
{
if(array[i-1][charToInt(position[1])-1] != '.')
{
printf("\n%s", "The position you choosed is not valid because there is oneother ship there");
return 2;
}
}
}
else
{
printf("\n%s", "The ship is going out of the bountries...");
return 2;
}
}
}
}
When position holds the string "A9 N", the printf correctly outputs 'N' for position[3]. For some reason when it tries to do if(position[3] == 'N'), however, a segmentation fault occurs.
Example program run:
Example of positioning: G3 E
Aircraft carrier (5 places), Give location and direction: A9 N
1
position[3] is: N but it doesn't work >_<
Well, based on your updates, it seems you have a variety of problems. For future reference, actually adding in the (possibly simplified) code showing how you were calling the function in question is better than trying to describe it using prose in a comment. There will be less guesswork for the people trying to help you.
If I'm reading your comment correctly, the code that calls validPosition looks something like this:
// "r and c are 9 and 9 in the specific example(rows columns)."
int rows = 9;
int columns = 9;
// "slots=5."
int slots = 5;
// "array is a 2d array and it contains characters(created with malloc)."
char **array = malloc(rows * columns * sizeof(char));
// "i created char position[10] in the function that called this function"
char position[10];
// "and with fgets(position, 10, stdin); i putted A9 N inside it."
fgets(position, 10, stdin);
validPosition(array, rows, columns, position, slots);
The first problem is your description of the allocation of array (I apologize if I misunderstood your comment and this isn't actually what you are doing). It should look similar to the code below for a dynamically sized two-dimensional array used with two subscripting operations (array[index1][index2], as it is in validPosition). Pointers-to-pointers (char **array) act differently than fixed sized multi-dimensional arrays (array[SIZE1][SIZE2]) when you access them that way.
// each entry in array should be a pointer to an array of char
char **array = malloc(rows * sizeof(char*));
for(i = 0; i < rows; i++)
array[i] = malloc(columns * sizeof(char));
You also need to be careful about using position after the fgets call. You should check the return value to make sure it isn't NULL (indicating an EOF or error condition). The string may not be \0-terminated in this case. In fact, all the elements may still be uninitialized (assuming you didn't initialized them before the call). This can lead to undefined behavior.
The next issue is that validPosition does not return a value on every code path. One example is if strlen(position) != 5. The other is if you enter the for loop and array[i-1][charToInt(position[1])-1] != '.' is never true (that is, the ship placement is deemed valid).
As strange as it is for an English speaker to say this to a Greek author, lets ignore internationalization and focus only on the default C local. The checks on position[0] should therefore be sufficient, though you might consider allowing your users to use lowercase letters as well. When converting position[1] from 1-based to 0-based, however, you do not account for the case when it is '0', which will result in charToInt returning -1. Furthermore, you're erroneously doing the subtraction again in the second array subscript of array[i-1][charToInt(position[1])-1].
Similarly, as pointed out by Jite and BLUEPIXY, you are doing two extra subtractions on the result of charToInt(position[0]): one in the for loop initializer (i=charToInt(position[0])-1) and one in the first array subscript of array[i-1][charToInt(position[1])-1].
Once you fix that, you might find that you are sometimes incorrectly telling the user that their selection is invalid. This is because you are checking charToInt(position[0]) + slots < r instead of <= r.
As I mentioned in my comment, one of the accesses to array is very probably the culprit behind your segmentation violation, not position[3] == 'N'. The reason you don't see the output of printf("\n%s", "come on"); is that your stdout appears to be line-buffered and there's no end of line to flush it. It is generally automatically flushed on normal program termination, however you're seg-faulting so that doesn't happen.
Finally, these are only the semantic errors I noticed. Stylistically, the code could also stand to be improved. For instance, it seems you're going to be implementing else if(position[3] == 'E', else if(position[3] == 'W', and else if(position[3] == 'S' clauses with similar logic to your if(position[3] == 'N' clause. This increases the likelihood you'll introduce an error by incorrectly copying-and-pasting and also increases your work later when you need to make a change in four places instead of one.
Since the terminology 'Segmentation Fault' I believe you are on Linux machine.
Use gdb to find the cause of error. Here are the steps.
Compile with additional -g flag (ex. gcc -g my_prog.c)
Run debugger: gdb a.out
Use 'list' command to find the line for break point (eg. first line of your function)
Set breakpoint on that line with: b 25 (if 25 is that line)
Run program with 'run' command
Use command 'next' to execute next line of code
Now the execution will pause on that line, you can examine memory, print variable contents
and stuff. But generally you want to determine on which line the execution fails and what was in which variable.
With a little playing with memory, you will easily find where the problem is. Personally, my code wont work with gdb support.
Perhaps segmentation fault at array[i-1][charToInt(position[1])-1]
i:charToInt(position[0])-1 : charToInt('A') - 1 : -1 <- Array out-of-bounds

Resources