Why does this code gives segmentation fault with some inputs? - c

//difference of two diagonals of a N x N matrix
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int N, j, i,k,l;
scanf("%d",&N);
int array[N-1][N-1], sum1=0, sum2=0, sum=0;
for(i=0;i<N; i++)
{
for(j=0; j<N; j++)
{
scanf("%d",&array[i][j]);
}
}
for(k = 0; k<N; k++){
sum1 += array[k][k];
}
for(l=0; l<N; l++){
sum2 += array[N-1-l][l];
}
sum = abs(sum1 - sum2);
printf("%d",sum);
return 0;
}
The above code generates segmentation fault for some inputs. The program calculates absolute difference between the summation of all the values in the two main diagonal.

The main problem, I think, is that you're declaring your array of size N - 1 × N - 1, but then filling in N elements. Do try declaring it N×N.

You declared array array as having N-1 rows and N-1 columns
int array[N-1][N-1], /*...*/;
So the valid range of indices for rows and columns of the array is [0, N-2]
However in the loops of the program you are trying to access elements of the array with indices N-1. For example
for(i=0;i<N; i++)
{
for(j=0; j<N; j++)
{
scanf("%d",&array[i][j]);
}
}
that is you are trying to access memory beyond the array and as result the program has undefined behaviour.
Simply write the declaration of the array like
int array[N][N], /*...*/;
Take into account that the sizes of the array shall be positive values.
Also you may remove headers
#include <string.h>
#include <math.h>
because no declaration from the headers is used in the program.

First of all, invalid input will cause Undefined Behavior.
You need to ensure that the input is valid, for that you can check scanf()'s return value, like this
if (scanf("%d", &N) != 1)
return -1;
Then you need to ensure that N > 0, because you allocate space for N - 1 items, so
if (N <= 1) /* this also prevents `int array[0][0];' */
return -1;
should be added.
Then you have to fix your loops, you allocate space for N - 1 items but you do N iterations from 0 to N - 1, N - 1 is an invalid index if you have only allocated N - 1 elements, you need to do one of two things
Fix the loop
for (int i = 0 ; i < N - 1 ; ++i) /* ... etc. */
Allocate space for N elements,
int array[N][N];
in this case you should change the check on N, to
if (N < 1)
return -1;
The reason why different input triggers different behavior, is because accessing an array beyond it's limits causes undefined behavior. So it will sometimes work some other times it will cause a segmentation fault and even some other times something else because it's undefined.
But there is yet another source of undefined behavrior that also depends on input and it's the way you used scanf(). If you type asdasd then N will be uninitialized when you declare your array variable, hence undefined behavior will happen too.

Related

Random swap of array elements- stack smashing detected

In my program to swap array elements randomly, value of j is determined as shown below:
int j = rand() % (i+1);
Instead of (i+1), I tried using i, i+2 which returned valid output.
But for i+3 onward invalid outputs occur,sometimes with an error as:
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)
Can someone please explain why only a value less than 3 must be added?
Program code is as shown below:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap (int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void printArray (int arr[], int n)
{
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
void randomize ( int arr[], int n )
{
srand ( time(NULL) );
for (int i = n-1; i > 0; i--)
{
int j = rand() % (i+1);
swap(&arr[i], &arr[j]);
}
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
int n = sizeof(arr)/ sizeof(arr[0]);
randomize (arr, n);
printArray(arr, n);
return 0;
}
Thank you in advance :)
Instead of (i+1), I tried using i, i+2 which returned valid output. But for i+3 onward invalid outputs occur
For anything greater than i+1 (such as i+2, i+3, etc), the resulting index j from:
int j = rand() % (i+2);
might be, depending on what rand() returns, outside the bounds of the array arr and thus it could result in undefined behaviour.
Can someone please explain why only a value less than 3 must be added?
That's not correct conclusion, either. As said you can't add anything greater 1. It's so happens to "work" with 2 (as with anything undefined behaviour, you just can't rely on it and should avoid it).
You can print the value of j and see for yourself whether it could be outside the bounds of the array.
Your array has n elements in it, and the indexes of those elements range from 0 to n-1.
When you choose a new index with rand() % (i+1), this results in a value from 0 to i. Since i starts at n-1 and goes down to 0, this gives you an index that is in range.
If you use rand() % (i+2) for your random index, the resulting values range from 0 to i+1. On the first iteration of the loop i is equal to n-1, which means you could get the value n as a result, which is out of the range of the array.
At this point, the problem can only occur on the first iteration, and only if the random value is n, so the chance if this happening is about 1 out of 9 runs so it won't happen all the time. If you use i+3, the chance of going out of range doubles on the first iteration of the loop, plus it could happen on the next iteration.
The proper way to generate a random value here is rand() % (i+1). Anything larger than i+1 risks going out of range, and the risk goes up the larger the value is.

How to store the sum of two integers into a long variable in C?

I created a matrix of ints for example have {1 , 2 , 3 , 4 , 5}
and then I'm trying to store the sum of the matrix into a long variable:
#include<stdio.h>
#define m 5
int main (){
int i;
int matrix[m];
long matrix_sum;
for(i = 0; i < m ; i++) //filling the matrix
matrix[i] = matrix[i-1]+1;
for(i = 0; i < m ; i++) //adding ints to long
matrix_sum += matrix[i];
printf("%lo \n",matrix_sum);
return 0;
}
when I run this code I have "17" on output instead of "15" !!
Think about what happens on the first iteration of this loop:
for(i = 0; i < m ; i++) //filling the matrix
matrix[i] = matrix[i-1]+1;
Notice that you'll be reading from index -1 of this array (oops!) This leads to undefined behavior, which means that in principle anything can happen. Your program could get garbage data, get the wrong answer, or even outright crash!
It's up to you to decide how to avoid this case. Consider changing the loop indices so that you start at a higher index.
Also, look at the remaining variables in main. Are they initialized? If not, adding values to them will again result in undefined behavior and pretty much anything can happen to them.
Finally, look at how you're printfing things:
printf("%lo \n",matrix_sum);
The %lo specifier means "the argument is a long, and it should be printed in octal (base-8)." This means that you're not printing the value in decimal, so even if you'd expect to get the value 15dec, you'd instead see 17, the octal representation of the number.
I have not seen a matrix. It seems you mean an array or a vector.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
The variable matrix_sum was not initialized.
In this loop
for(i = 0; i < m ; i++) //filling the matrix
matrix[i] = matrix[i-1]+1;
^^^^
there is an attempt to access memory beyond the array when the variable i is equal to 0.
And it looks like you wanted to use the conversion specifier %ld in this statement
printf("%lo \n",matrix_sum);
^^^
Otherwise the output will be as an octal number.
I think you mean the following. At least the program output is exactly equal to 15.:)
#include <stdio.h>
#define N 5
int main(void)
{
int a[N];
int i;
long sum;
for ( i = 0; i < N ; i++ ) a[i] = i + 1;
sum = 0;
for ( i = 0; i < N ; i++ ) sum += a[i];
printf( "%ld\n", sum );
return 0;
}

C - Passing a 3D arrays of chars to a function

I'm trying to write a program that analyzes a (3 x 4) matrix of strings provided by the user. Ultimately, it needs to output the longest string present in the matrix, along with that string's length.
My program seems to read the input correctly, as judged its success in echoing back the input strings, but it does not correctly output the longest word. I'm sure I'm committing some kind of pointer-related error when I pass the value of longest word, but I do not have any idea how to solve it.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define M 4
#define N 5
#define MAX_DIM 20
void findMAX(char matrice[N][M][MAX_DIM]) {
char maxr;
int index;
int i, j, it;
index = 0;
maxr = *(*(*(matrice+0)+0)+MAX_DIM);
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
if (index < strlen(matrice[i][j])) {
index = strlen(matrice[i][j]);
// I save the longer line's value
it = i;
// I save the maximum's value
maxr = *(*(*(matrice+i)+j)+MAX_DIM);
}
}
}
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
printf ("It is content in the: %d line, which is: \n", it);
for (j = 0; j < N-1; j++) {
printf("%s ", matrice[it][j]);
}
}
void leggi(char matrice[N][M][MAX_DIM]) {
int i, j;
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
printf ("Insert the element matrix [%d][%d]: ", i, j);
scanf ("%s", matrice[i][j]);
fflush(stdin);
}
}
}
void stampa(char matrice[N][M][MAX_DIM]) {
int i, j;
printf("\n(4 x 3) MATRIX\n");
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
printf("%s ", matrice[i][j]);
}
printf("\n\n");
}
}
int main(int argc, char *argv[]) {
char matrix[N][M][MAX_DIM]; //Matrix of N*M strings, which are long MAX_DIM
printf("************************************************\n");
printf("** FIND THE LINE WITH THE MAXIMUM ELEMENT **\n");
printf("** IN A (4 x 3) MATRIX **\n");
printf("************************************************\n");
printf ("Matrix Reading & Printing\n");
leggi (matrix);
stampa (matrix);
findMAX(matrix);
return 0;
}
First of all to address some misconceptions conveyed by another answer, consider your 3D array declared as
char matrix[N][M][MAX_DIM];
, where N, M, and MAX_DIM are macros expanding to integer constants.
This is an ordinary array (not a variable-length array).
If you want to pass this array to a function, it is perfectly acceptable to declare the corresponding function parameter exactly the same way as you've declared the array, as indeed you do:
void findMAX(char matrice[N][M][MAX_DIM])
But it is true that what is actually passed is not the array itself, but a pointer to its first element (by which all other elements can also be accessed. In C, multidimensional arrays are arrays of arrays, so the first element of a three-dimensional array is a two-dimensional array. In any case, that function declaration is equivalent to both of these:
void findMAX(char (*matrice)[M][MAX_DIM])
void findMAX(char matrice[][M][MAX_DIM])
Note in particular that the first dimension is not conveyed. Of those three equivalent forms, I find the last clearest in most cases.
It is quite odd, though, the way you access array elements in your findMAX() function. Here is the prototypical example of what you do:
maxr = *(*(*(matrice+i)+j)+MAX_DIM);
But what an ugly and confusing expression that is, especially compared to this guaranteed-equivalent one:
maxr = matrice[i][j][MAX_DIM];
Looking at that however, and it how you are using it, I find that although the assignment is type-correct, you are probably using the wrong type. maxr holds a single char. If you mean it to somehow capture the value of a whole string, then you need to declare it either as an array (into which you will copy strings' contents as needed), or as a pointer that you will set to point to the string of interest. The latter approach is more efficient, and I see nothing to recommend the former for your particular usage.
Thus, I think you want
char *maxr;
... and later ...
maxr = matrice[0][0];
... and ...
maxr = matrice[i][j];
That sort of usage should be familiar to you from, for example, your function stampo(); the primary difference is that now you're assigning the expression to a variable instead of passing it directly to a function.
And it turns out that changing maxr's type that way will correct the real problem here, which #AnttiHaapala already pointed out in comments: this function call ...
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
requires the second argument (maxr) to be a pointer to a null-terminated array of char in order to correspond to the %s directive in the format string. Before, you were passing a single char instead, but with this correction you should get mostly the expected result.
You will probably, however, see at least one additional anomaly. You final loop in that function has the wrong bound. You are iterating with j, which is used as an index for the second dimension of your array. That dimension's extent is M, but the loop runs to N - 1.
Finally, I should observe that it's odd that you allocate space for a 5 x 4 array (of char arrays) and then ignore the last row and column. But that's merely wasteful, not wrong.
Try something like this:
void findMAX(char matrice[N][M][MAX_DIM]){
// char maxr
char maxr[MAX_DIM];
int index;
int i, j, it;
index = 0;
// maxr = *(*(*(matrice+0)+0)+MAX_DIM);
strncpy(maxr, *(*(matrice+0)+0), MAX_DIM);
for (i = 0; i < N-1; i++)
{
for (j = 0; j < M-1; j++)
{
if (index < strlen(matrice[i][j]))
{
index = strlen(matrice[i][j]);
it = i;
// maxr = *(*(*(matrice+i)+j)+MAX_DIM);
strncpy(maxr, *(*(matrice+i)+j), MAX_DIM);
}
}
}
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
printf ("It is content in the: %d line, which is: \n", it);
// for (j = 0; j < N-1; j++){
for (j = 0; j < M-1; j++){
printf("%s ", matrice[it][j]);
}
}
It's possible to pass multi-dimensional arrays to C functions if the size of the minor dimensions is known at compile time. However the syntax is unacceptable
void foo( int (*array2d)[6] )
Often array dimensions aren't known at compile time and it is necessary to create a flat array and access via
array2D[y*width+x]
Generally it's easier just to use this method even if array dimensions are known.
To clarify in response to a comment, C99 allows passing of variable size arrays using the more intuitive syntax. However the standard isn't supported by Microsoft's Visual C++ compiler, which means that you can't use it for many practical purposes.

what is the segmentation fault in this program

#include<stdio.h>
#include <stdlib.h>
int main()
{
int n,small=0,large=0,s,l,temp;
printf("this should work");
scanf("%d",&n);
// printf("%d",n);//
int a[n];
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
/* for(int i=0;i<n;i++)
printf("%d",a[i]);*/
small=a[0];
large=a[n-1];
for(int i=0;i<n;i++)
{
if(a[i]<small && i!=0)
{
small=a[i];
s=i;
}
if(a[i]>large && i!=n-1)
{
large=a[i];
l=i;
}
}
temp=a[s];
a[s]=a[l];
a[l]=a[s];
for(int i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
This is a simple program to swap the largest and smallest number in an array and print the new array.
When I tried to run this program I got a segmentation fault.
Usually, a segmentation fault occurs when we try to access an out of bound memory location.
So I added printf statements to find out where the error is.
But none print statements were executed. what is the error here ?
One problem is that you don't actually set s and l to anything unless you find an element that is smaller/larger than the current one.
That means (for example), if the first element is the smallest, s will be set to some arbitrary value and trying to index the array with it could be problematic.
To fix that, where to set small and large, you should also set:
s = 0;
l = n - 1;
In addition, your swap code is wrong and should be:
temp = a[s];
a[s] = a[l];
a[l] = temp;
You should initialize s and l to some value because when the if condition does not works their values will remain uninitialized garbage values. Hence, a[l] or a[s] will not work, since these indexes are undefined values. That is why you will get segmentation fault because you are accessing an undefined area of an array.
So, use random values within array range like s=0,l=0 to initialize the variables or you can add some flags to check if the conditions are working.
if (l != 0 && s != 0) {
temp=a[s];
a[s]=a[l];
a[l]=a[s];
}
Also, I think you are swapping the values so in the last line a[l]=temp instead of a[l]=a[s].
ideone link
You cannot declare an array based on a dynamic size, unless the compiler supports it and even then it is generally not portable.
int a[n]
you actually need to use malloc or calloc.
int *a;
a = (int *)malloc(n * sizeof(int)); or a = (int *)calloc(n, sizeof(int));

Trying to access array element in loop causes segmentation fault, why?

I am trying to create a two dimensional array, which has either 1 or 0 randomly assigned to each coordinate. It works just fine until it gets to the coordinates [20][3]. After that it just throws out "segmentation fault 11".
I am absolutely clueless how or why. Especially since I can create a matrix with 200 * 200 for instance but it still gets the same Problem only at the coordinates [200][3]. So it is somehow always the third y coordinate in the last x coordinate where the error occurs.
#include <stdio.h>
#include <stdlib.h>
int main() {
int x, y, i, j ;
x = 20;
y = 20;
int grid [x][y];
for ( i = 0; i <= x; i++) {
for ( j = 0; j <= y; j++) {
grid[i][j] = rand() % 2 ;
printf("grid [%d][%d]: %d\n", i, j, grid[i][j]);
}
}
return 0;
}
C uses 0-based indexing for arrays. So, for an array defined as
int grid [x][y]
looping for
for ( i = 0; i <= x; i++)
for ( j = 0; j <= y; j++)
if off-by-one. (Note the <= part).
to elaborate, for an array of dimension p, the valid indexes are 0 to p-1, inclusive.
You should change your loop conditions as i < x and j < y to stay withing the bounds. Accessing out of bound memory causes undefined behavior.
That said,
int main() should be int main(void), at least, to conform to C standards for hosted environments.
There is no need to make grid as VLA here. If the dimensions are already known, better approach is to use a compile-time constant (#define) to generate the array dimensions.
You're running past the bounds of the array. That's undefined behaviour in C, and is manifesting itself as a crash.
Change i <= x to i < x etc, or increase the grid size.

Resources