Stack smashing error when manipulating array of ints in function - c

So I'm trying to make a simple program that takes an array that is partially full and adds an integer to the beginning shifting all existing elements to the right. It seems what I have here adds and shifts things properly but once all the code executes, I get a stack smashing detected error.
Here is my code:
#include <stdio.h>
void addCommand(int *, int, int);
void main() {
int i;
int list[10];
list[0] = 1;
list[1] = 5;
printf("Before add:\n");
for (i = 0; i < 2; i++) {
printf("%d\n", list[i]);
}
addCommand(list, sizeof(list), 4);
printf("Adding 4:\n");
for (i = 0; i < 3; i++) {
printf("%d\n", list[i]);
}
}
void addCommand(int *arr, int size, int new) {
int k;
printf("%d", arr[0]);
for (k = size - 1; k >= 0; k--) {
if (&arr[k] != NULL) {
if (k > 0) {
arr[k] = arr[k-1];
} else {
arr[k] = new;
}
}
}
}
And here's the output:
If anyone could point out what I'm doing wrong here, it would be much appreciated!

addCommand(list, sizeof(list), 4);
above line doesn't pass number of element in list array. you have to do something like this:
sizeof(arr)/sizeof(arr[0])

Related

why does the printf not showing

I need help. It doesnt display the printf in the mean function. I am doing a dynamic allocation in c and the add function works but the mean function does not display. There is no problem to the add function it works but the max does not. I am sorry I know this problem is simple but still cant get the answer. I am also getting a warning to the add function during the call in main.
This is my code:
typedef int* Statistician;
void add(Statistician answer, int *count, int *SIZE, int item);
|
[Note] expected 'Statistician' {aka 'int *'} but argument is of type 'int **'
int main() {
int SIZE;
Statistician *answer;
int count;
int item;
add(answer, count, SIZE, item);
|
//[Warning] passing argument 1 of 'add' from incompatible pointer type [-Wincompatible-pointer-types]
printf("\nThe mean is: %.2f", mean(answer, SIZE));
return 0;
}
This is the add function:
void add(Statistician answer, int *count, int *SIZE, int item) {
int i;
printf("Enter n: ");
scanf("%d", &item);
answer = (int*)malloc(item * sizeof(int));
if(item == NULL) {
printf("Memory not allocated.\n");
exit(0);
}
else {
for(i = 0; i < item; ++i) {
scanf("%d", &answer[i]);
}
printf("Elements of array are: ");
for(i = 0; i < item; i++) {
printf("%d ", answer[i]);
}
if(item == 10) {
int m;
printf("\nAppend array: ");
scanf("%d", &m);
answer = realloc(answer, m * sizeof(int));
for(i = item; i < item + m; i++) {
scanf("%d", &answer[i]);
}
item = item + m;
int temp, j;
for(i = 0; i < item; i++) {
for(j = 0; j <= i; j++) {
if(*(answer + i) < *(answer + j)) {
temp = *(answer + i);
*(answer + i) = *(answer + j);
*(answer + j) = temp;
}
}
}
printf("Final array: \n");
for(i = 0; i < item; ++i) {
printf("%d ", answer[i]);
}
}
}
}
This is the max function that doesnt display:
float mean(Statistician answer, int count) {
int mean =0;
int cnt = 0;
for(int i=0;i<count;i++){
mean = mean + answer[i];
cnt++;
}
mean = mean / cnt;
return mean;
}
I fully expected to find a duplicate but I didn't.
The first argument to add is declared to be int ** (via typedef) and you passed it a paramter of type int *. The compiler will let you do this with a warning, but it's almost always wrong. Don't do it.
If you're running 64 bit code, anything can happen after you stomp memory. 32 bit code is slightly more predictable but it's still going to end badly.
From your code, it looks like you want void add(Statistician *answer, Statistician answer; and add(&answer.
The deep learning of pointers is here. The thing you need to modify in the calling function is the thing whose address is passed to the called function. Allocating arrays with malloc almost always ends up being double pointers.

Why do i get segmentation fault 11?

Why do I get segmentation fault 11? I get it quite often, and I know this time it is about the function. If anyone can help, please do, the code is down below! I am trying to make a program, that WITH A FUNCTION, can rearrange an array in ascending order and then print it in main in reverse order.
#include "stdio.h"
void changxr(int *counter, int *arrsize, int *j, int *arr[]);
int main()
{
int a, i, j, counter;
int arrsize;
int arr[100];
printf("pick an arraysize: \n");
scanf("%d", &arrsize);
printf("type %d numbers \n", arrsize);
for (counter = 0; counter < arrsize; counter++)
{
scanf("%d", &arr[counter]);
}
for (int c = arrsize - 1; c >= 0; c--)
{
printf("%d ", arr[c]);
}
changxr(&counter, &arrsize, &j, &arr[&counter]);
for (counter = arrsize - 1; counter >= 0; counter--)
{
printf("%d ", arr[counter]);
}
}
void changxr(int *counter, int *arrsize, int *j, int *arr[])
{
int a;
for (*counter = 0; *counter < *arrsize; *counter++)
{
for (*j = *counter + 1; *j < *arrsize; *j++)
{
if (*arr[*counter] > *arr[*j])
{
a = *arr[*counter];
*arr[*counter] = *arr[*j];
*arr[*j] = a;
}
}
}
}
New code:
#include "stdio.h"
void changxr(int arrsize, int *arr[]);
int main()
{
int a, i, j, counter;
int arrsize;
int arr[100];
printf("pick an arraysize: \n");
scanf("%d", &arrsize);
printf("type %d numbers \n", arrsize);
for (counter = 0; counter < arrsize; counter++)
{
scanf("%d", &arr[counter]);
}
for (int c = arrsize - 1; c >= 0; c--)
{
printf("%d ", arr[c]);
}
changxr(arrsize, &arr[counter]);
for (counter = arrsize - 1; counter >= 0; counter--)
{
printf("%d ", arr[counter]);
}
}
void changxr(int arrsize, int *arr[])
{
int a, counter, j;
for (counter = 0; counter < arrsize; counter++)
{
for (j = counter + 1; j < arrsize; j++)
{
if (*arr[counter] > *arr[j])
{
a = *arr[counter];
*arr[counter] = *arr[j];
*arr[j] = a;
}
}
}
}
This is what I got from debugging:
"Program received signal SIGSEGV, Segmentation fault.
0x0000555555555355 in changxr (arrsize=3, arr=0x0) at main.c:33
33 for(j=counter+1; j<arrsize; j++) { if(*arr[counter]>*arr[j]){
(gdb) continue"
You do not need two levels of indirection (int *arr[], *arr[counter], *arr[j]). When arr is passed to a function, it will decay to a pointer-to-its-first-element, or more simply, an int *.
&arr[counter] is also an int *, but it is the address of the array element one past the elements you've initialized. This would start your sorting function in the incorrect place.
Your program segfaults because it attempts to use this value as an int ** (int *[]).
gcc -Wall highlights this clearly:
prog.c: In function ‘main’:
prog.c:24:22: warning: passing argument 2 of ‘changxr’ from incompatible pointer type [-Wincompatible-pointer-types]
24 | changxr(arrsize, &arr[counter]);
| ^~~~~~~~~~~~~
| |
| int *
prog.c:3:32: note: expected ‘int **’ but argument is of type ‘int *’
3 | void changxr(int arrsize, int *arr[]);
| ~~~~~^~~~~
Things to do:
Simply pass the array and the length of the array to your function.
Use a single level of indirection in your function definition, and when accessing the array.
Use a variable-length array.
Use an auxiliary function for printing.
Declare variables when you need them, in the correct scope.
You should also consider checking the return value of scanf is the expected number of successful conversions.
The refactored code:
#include <stdio.h>
void changxr(int *a, size_t length)
{
for (size_t i = 0; i < length; i++) {
for (size_t j = i + 1; j < length; j++) {
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
void print_reverse(int *a, size_t length)
{
printf("[ ");
while (length--)
printf("%d ", a[length]);
printf("]\n");
}
int main(void)
{
size_t size;
printf("Pick an array length: ");
if (1 != scanf("%zu", &size) || size == 0) {
fprintf(stderr, "Invalid length input.\n");
return 1;
}
int array[size];
printf("Enter %zu numbers:\n", size);
for (size_t i = 0; i < size; i++) {
if (1 != scanf("%d", array + i)) {
fprintf(stderr, "Invalid integer input.\n");
return 1;
}
}
printf("Array (in reverse): ");
print_reverse(array, size);
changxr(array, size);
printf("Array, Sorted (in reverse): ");
print_reverse(array, size);
}

Storing Fibonacci numbers in an array (C)

Can't get my program to output the correct number. I feel like I am making a simple mistake. This is written in C.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n, i;
int list[n];
while(1)
{
scanf("%d", &n);
if(n == -1)
{
break;
}
else
{
for(i = 2; i < n; i++)
{
list[i] = list[i-1]+list[i-2];
}
printf("%d %d", i, list[i] );
}
}
}
(To make things simpler, I'm going to ignore dealing with input.)
First problem is turning on compiler warnings. Most C compilers don't give you warnings by default, you have to ask for them. Usually by compiling with -Wall. Once we do that, the basic problem is revealed.
test.c:6:14: warning: variable 'n' is uninitialized when used here [-Wuninitialized]
int list[n];
^
test.c:5:10: note: initialize the variable 'n' to silence this warning
int n, i;
^
= 0
1 warning generated.
int list[n] immediately creates a list of size n. Since n is uninitialized it will be garbage. You can printf("%d\n", n); and see, it'll be something like 1551959272.
So either n needs to be initialized, or you need to reallocate list dynamically as n changes. Dynamic allocation and reallocation gets complicated, so let's just make it a static size.
So we get this.
#include <stdio.h>
#include <stdlib.h>
int main() {
/* Allocate an array of MAX_N integers */
const int MAX_N = 10;
int list[MAX_N];
/* Do Fibonacci */
for(int i = 2; i < MAX_N; i++) {
list[i] = list[i-1]+list[i-2];
}
/* Print each element of the list and its index */
for( int i = 0; i < MAX_N; i++ ) {
printf("%d\n", list[i]);
}
}
That runs, but we get nothing but zeros (or garbage). You have a problem with your Fibonacci algorithm. It's f(n) = f(n-1) + f(n-2) with the initial conditions f(0) = 0 and f(1) = 1. You don't set those initial conditions. list is never initialized, so list[0] and list[1] will contain whatever garbage was in that hunk of memory.
#include <stdio.h>
#include <stdlib.h>
int main() {
/* Allocate an array of MAX_N integers */
const int MAX_N = 10;
int list[MAX_N];
/* Set the initial conditions */
list[0] = 0;
list[1] = 1;
/* Do Fibonacci */
for(int i = 2; i < MAX_N; i++) {
list[i] = list[i-1]+list[i-2];
}
/* Print each element of the list and its index */
for( int i = 0; i < MAX_N; i++ ) {
printf("%d\n", list[i]);
}
}
Now it works.
0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
Here is code snippet,
#include <stdio.h>
int main()
{
int MAX_SIZE = 100; //Initial value
int n, i;
int list[MAX_SIZE];
printf("Enter value of 'n'");
scanf("%d",&n);
if(n < 0){
printf("'n' cannot be negative number");
return 0;
}else if (n==1){
list[0]=0;
}else if(n == 2){
list[0]=0;
list[1]=1;
}else{
list[0]=0;
list[1]=1;
for(i = 2; i <= n; i++)
{
list[i] = list[i-1]+list[i-2];
}
}
//To view array elements
for(int i=0;i<n;i++){
printf("%3d",list[i]);
}
}
You don't have return in main function.
n must be defined previous. Otherwise it took random value from memory.
So, your list array is created with unknown value.
int list[n];
Also, this will never happends, becous n is declared, but not defined.
i < n;
Is this what you need?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int F[100];
F[0] = 0;
F[1] = 1;
int i = 2;
while(1)
{
if(i < 100)
{
F[i] = F[i-1] + F[i-2];
i++;
}
else
{
break;
}
}
i = 0;
while(1)
{
if(i < 100)
{
printf("%d ; ", F[i]);
i++;
}
else
{
break;
}
}
return 0;
}
You need to allocate memory on demand for each iteration. In your code, n is uninitalized which leads to unpredectiable behavior. Also you need to initialize list[0] and list[1] since this is the 'base' case.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n, i;
int* list; /* Declare a pointer to the list */
while(1)
{
scanf("%d", &n);
if(n == -1)
{
break;
}
else if ( n > 0 )
{
list = (int *) malloc( n * sizeof(int) );
list[0] = 1;
list[1] = 1;
for(i = 2; i < n; i++)
{
list[i] = list[i-1]+list[i-2];
}
printf("%d %d\n", i, list[i-1] );
free(list);
}
}
}

Printing only unique elements in an array

Edit: I need to maintain the order in which the elements are present in the original array, so sorting won't work.
I have a 1-D array containing some elements and I am using printf() in C but I only want to print an element if and only if it has not already been printed before.
I am thinking of using nested loops to compare if the element I am about to print from the current position in the array was already present in a lower index of the array but it's not working. What am I missing? Or is my whole approach wrong?
So far, I have tried this, which is not working:
int arr[20];
After this I take user input for no. of elements in p and of course, p<20. Then, user enters the elements one by one. I use scanf() for this.
for(i=1;i<=p;i++)
{
for(j=i+1;j<=p;j++)
{
if(arr[i]!=arr[j])
{
printf("%d",arr[j]);
}
}
}
You need to check all previous items before you know if the item has already occurred.
#include <stdio.h>
#include <stdlib.h>
int compareFunc(const void *op1, const void *op2 )
{
int *a, *b;
a = (int*)op1;
b = (int*)op2;
return *a - *b;
}
void printUnique(int *array, int numElems)
{
int curPrintIndex, curCompareIndex;
char alreadySeen;
for (curPrintIndex=0; curPrintIndex<numElems; curPrintIndex++)
{
alreadySeen = 0;
for (curCompareIndex=0; curCompareIndex<curPrintIndex; curCompareIndex++)
{
if (array[curCompareIndex] == array[curPrintIndex])
{
alreadySeen = 1;
break;
}
}
if (alreadySeen == 0)
printf("%d\n", array[curPrintIndex]);
}
}
int main()
{
const int numItems = 100;
int *array, i, lastVal;
array = calloc(numItems, sizeof(int) );
for (i=0; i<numItems; i++)
array[i] = rand()%numItems;
printUnique(array, numItems);
free(array);
return 0;
/*
qsort(array, numItems, sizeof(int), compareFunc);
printf("%d\n", array[0]);
lastVal = array[0];
for (i=1; i<numItems; i++)
{
if (array[i] != lastVal)
{
lastVal = array[i];
printf("%d\n", array[i]);
}
}
*/
}
#include <stdio.h>
int main(void){
int arr[20] = { 4,8,4,2,4,8,1,3,2,7 };//the elements are positive integers.
int i, j, p = 10;
for(i=0;i<p-1;i++){
if(arr[i] < 0)
continue;
for(j=i+1;j<p;j++){
if(arr[j] > 0 && arr[i]==arr[j])
arr[j] *= -1;
}
}
for(i=0; i < p; ++i)
if(arr[i] > 0)
printf("%d ", arr[i]);
puts("");
return 0;
}

Mergesort An Array of Strings in C

I'm trying to implement a merge sort for an array of strings entered from standard input, and am at a loss at what is wrong. Right now I'm facing a segmentation fault. How should I modify my code?
main() {
char temp;
int i = 0;
char Strings[NUM][LEN];
printf("Please enter %d strings, one per line:\n", NUM);
for (i; i < 25; i++) {
fgets(&Strings[i][0], LEN, stdin);
}
i = 0;
puts("\nHere are the strings in the order you entered:");
for (i; i < 25; i++) {
printf("%s\n", Strings[i]);
}
mergesort(Strings, NUM);
i = 0;
puts("\nHere are the strings in alphabetical order");
for (i; i < 25; i++) {
printf("%s\n", Strings[i]);
}
}
int mergesort(char list[NUM][LEN], int length) { // First part
mergesort_r(0, length, list);
return 0;
}
int mergesort_r(int left, int right, char list[NUM][LEN]) { // Overloaded portion
if (right - left <= 1) {
return 0;
}
int left_start = left;
int left_end = (left + right) / 2;
int right_start = left_end;
int right_end = right;
mergesort_r( left_start, left_end, list);
mergesort_r( right_start, right_end, list);
merge(list, left_start, left_end, right_start, right_end);
}
int merge(char list[NUM][LEN], int left_start, int left_end, int right_start, int right_end) {
int left_length = left_end - left_start;
int right_length = right_end - right_start;
char *left_half[left_length];
char *right_half[right_length];
int r = 0;
int l = 0;
int i = 0;
for (i = left_start; i < left_end; i++, l++) {
strcpy(left_half[l], list[i]);
}
for (i = right_start; i < right_end; i++, r++) {
strcpy(right_half[r], list[i]);
}
for (i = left_start, r = 0, l = 0; l < left_length && r < right_length; i++) {
if (strcmp(left_half[l], right_half[r]) < 0) {
strcpy(list[i], left_half[l++]);
} else {
strcpy(list[i], right_half[r++]);
}
}
for ( ; l < left_length; i++, l++) {
strcpy(list[i], left_half[l]);
}
for ( ; r < right_length; i++, r++) {
strcpy(list[i], right_half[r]);
}
return 0;
}
I'm not sure if it's that I'm passing in my array incorrectly, or maybe it's that I am not even executing swaps properly. I'm at my wits end with this and could use some advice.
should be
char left_half[left_length][LEN];
char right_half[right_length][LEN];
#include<stdio.h>
#include<stdlib.h>
#include<string.h> //To use the string functions like strcmp and strcpy
#define MAX 10 // This is the default size of every string
void Merge(char* arr[],int low,int mid,int high) //Merging the Array Function
{
int nL= mid-low+1;
int nR= high-mid;
char** L=malloc(sizeof(char *)*nL);
char** R=malloc(sizeof(char *)*nR);
int i;
for(i=0;i<nL;i++)
{
L[i]=malloc(sizeof(arr[low+i]));
strcpy(L[i],arr[low+i]);
}
for(i=0;i<nR;i++)
{
R[i]=malloc(sizeof(arr[mid+i+1]));
strcpy(R[i],arr[mid+i+1]);
}
int j=0,k;
i=0;
k=low;
while(i<nL&&j<nR)
{
if(strcmp(L[i],R[j])<0)strcpy(arr[k++],L[i++]);
else strcpy(arr[k++],R[j++]);
}
while(i<nL)strcpy(arr[k++],L[i++]);
while(j<nR)strcpy(arr[k++],R[j++]);
}
void MergeSort(char* arr[],int low,int high) //Main MergeSort function
{
if(low<high)
{
int mid=(low+high)/2;
MergeSort(arr,low,mid);
MergeSort(arr,mid+1,high);
Merge(arr,low,mid,high);
}
}
int main()
{
printf("\nEnter the size of the array desired: ");
int size; //This is the String array size
scanf("%d",&size);
char** arr= malloc(sizeof(char *)* size); //Creating required string array
printf("\nEnter the strings of the array: ");
int i;
for(i=0;i<size;i++)
{
arr[i]=malloc(sizeof(char)*MAX);
printf("\nEnter String: ");
scanf("%s",arr[i]);
}
MergeSort(arr,0,size-1);
printf("\nThe Sorted Array is: ");
for(i=0;i<size;i++)printf("%s ->",arr[i]);
return 0;
}
This is a Working solution to the same problem. Hope it Helps!
Cheers! :)
This solution of yours might give a memory error for long inputs or repeated executions. You need to free the allocated memory or not dynamically allocate it in the first place.
The latter is an easier option. What you can do is find the length of the longest string in the array of strings before hand and pass it as an argument to the merge sort and merge function.
Let's say that length is LEN.
Then instead of dynamically allocating memory for the L and R array, just declare it as:
char L[nL][LEN] and char R[nR][LEN].
It might take a slightly larger stack memory but avoids crashing the program.

Resources