some time ago I tried to program a Mergesort. In some point I got an error that I was able to solve, but still saved the code because have something strange that i don't understand. The code is the following:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef int elem;
void mergesort(elem * arr, unsigned n){
if(n != 1){
if(n == 2){
if(arr[0] > arr[1]){
int change = arr[0];
arr[0] = arr[1];
arr[1] = change;
}
}else{
unsigned i = 0, j = 0, mit = (n+1)>>2, fin = n>>2;
elem * arr_2 = (elem *)malloc(sizeof(elem) * n), * mit_arr = arr+mit;
mergesort(arr, mit);
mergesort(mit_arr, fin);
while(i < mit || j < fin){
if(arr[i] <= mit_arr[j]){
arr_2[j+i] = arr[i];
i++;
}else{
arr_2[j+i] = mit_arr[j];
j++;
}
}
for(i=0; i<n; i++)
arr[i] = arr_2[i];
free(arr_2);
}
}
}
int main(){
unsigned a = 10;
int i;
elem * arr = (elem*)malloc(sizeof(elem) * a);
arr[0] = 12;
arr[1] = 3;
arr[2] = -3;
arr[3] = 22;
arr[4] = 12;
arr[5] = 11;
arr[6] = 4;
arr[7] = 9;
arr[8] = 10;
arr[9] = 2;
printf("something\n"); // 1
mergesort(arr, a);
printf("\n");
for(i=0; i<a; i++){
printf("%d, ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
The thing is that, despite the fact that the code doesn't do what I want and it seems like there is no error, if I comment out the line marked by 1 (printf("something\\n"); ) then the error "malloc(): corrupted top size" appears. I actually don't know why something like that is possible, so I came here to see if someone have an explanation.
I tried to debug the program with gdb and got the same error, but have more information:
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
but still without idea of what happened.
There are a couple of major issues with your code. These are things you should be able to test yourself by checking whether the values being used by your function are what you expect.
Here's the first issue. You have calculated the length of the first half of the array as (n+1)>>2, and then you assume the length of the remaining array is n>>2. That is simply not true. Shifting a value to the right by 2 binary places is a division by four.
It is far better to use "normal" math instead of attempting to be clever. This reduces the chance for errors, and makes your code easier to read.
unsigned mit = n / 2, fin = n - mit;
The other issue is your merge. You have made your while-loop run until both i and j are out-of-range. But in your loop, it's guaranteed that on at least one of the iterations, one of those values will be out-of-range.
A better way to merge arrays uses three loops. The first one runs until either of the arrays has been merged in, and the remaining two loops will copy the remaining part of the other array.
unsigned x = 0, i = 0, j = 0;
while(i < mit && j < fin){
if(arr[i] <= mit_arr[j]){
arr_2[x++] = arr[i++];
}else{
arr_2[x++] = mit_arr[j++];
}
}
while(i < mit){
arr_2[x++] = arr[i++];
}
while(j < fin){
arr_2[x++] = mit_arr[j++];
}
Related
The segmentation error occurs in this function:
#include <stdio.h>
#include <stdlib.h>
int heap [999],heap2 [999];
int* addDigit(int *arr, int SIZE, int D) {
int con=0;
for (int i = 0; i < SIZE; i++)
con = con * 10 + arr[i];
con += D;
int p = 0;
while (con >= 0) {
heap[p] = con % 10;
con /= 10;
p++;
}
for (int i = 0; i < p; i++)
printf("%d ", heap[i]);
heap2[0] = 11;
heap2[1] = -1;
int *pp = heap2;
return pp;
}
This is main function:
int main() {
int N, digit;
scanf("%d", &N);
int arr[N];
for (int index = 0; index < N; index++) {
scanf("%d", &arr[index]);
}
scanf("%d", &digit);
int *ptr = addDigit(arr, N, digit);
int index = 0;
while (*(ptr+index) !=-1) {
printf("%d", ptr[index]);
index++;
}
return 0;
}
Why am I getting a segmentation fault here?
This program gets input of array like [1 2 3] and value k, say 3;
it should print 1 2 6.
I used two globally declared arrays here.
Generally, the quickest way to locate the sources of segmentation faults, is the compile the program with the -g flag to include debug information in the executable, and then to run the program using Valgrind.
In this case, the segmentation fault occurs in the reading of heap here:
while (con >= 0)
{
heap[p] = con % 10;
con /= 10;
p++;
}
The variable con will eventually become 0 and will stay at 0 due to the repeated division by 10. It will not become negative, and thus the while-loop will repeat infinitely. The index p will increase until the program will try to access element 999 of heap - which is out of bounds, i.e. this is a segmentation fault.
Perhaps you meant to write while (con > 0)? This stop the loop when con is zero (instead of negative, as before). Or perhaps you need a different solution, depending on what the intended functionality of the code is exactly.
PS. The segmentation fault does not happen "in the compiler", it occurs while the program is executed.
Just a basic program, written by a newbie. Supposed to read in values into a dynamic array, then print them out in reverse order. You can't input the size of array beforehand, the array's size will adjust as long as inputs aren't terminating characters.
I think I wrote it okay, but there are errors about dereferencing pointers and when I run it in VS, it won't even register inputs. When attempted in other compiler, it does register the input, but doesn't terminate with "-1".
Thinking about it, looking it up, I don't notice my mistake, hope you will help me.
Edit: thanks for pointing out the semicolon after while, but now it's a "Heap Corruption Error" after inputting 2 or 3 inputs. What went wrong?
int i=0;
int *p, *a;
int n=1;
p = (int*)malloc(n * sizeof(int));
printf("Enter integers here, and input -1 when done:\n");
while (p[i] != -1);
{
scanf_s("%d", &p[i]);
n = i + 1;
a= (int*)malloc(n * sizeof(int));
for (int j = 0; j < n; ++j)
{
a[j] = p[j];
}
free(p);
p = NULL;
p= (int*)malloc(n * sizeof(int));
for (int k = 0; k < n; ++k)
{
p[k] = a[k];
}
free(a);
a = NULL;
++i;
}
--i;
if (i <= 0)
{
printf("%d", p[i]);
--i;
}
free(p);
p = NULL;
while (p[i] != -1);
remove the trailing ;.
Also malloc gives you uninitialized memory, so chances are that the condition is not true at the first iteration. You probably want a do { ... } while(...); loop.
Reformatting your code reveals the (or at least a) bug:
int i = 0;
int *p, *a;
int n = 1;
p = (int *)malloc(n * sizeof(int));
printf("Enter integers here, and input -1 when done:\n");
while (p[i] != -1)
;
{
scanf_s("%d", &p[i]);
// ...
There's a stray semicolon after the first while, making it an infinite loop of nothing.
I am working on a class project to solve the wandering Salesman problem, which is basically the TSP, except you don't return to the source. I took the approach of finding all possible permutations of a set of vertices and then iteratively calculating the length and comparing them to find the smallest. I know it's not the best approach, but its what our professor wanted.
When I run the code below, it works fine and gives me the right answers when the input array is less than 7 X 7. But when its 7 X 7, it returns "Bus Error: 10", and if the size is 12 x 12, it returns "Segmentation Fault : 11". I looked up these problems for hours and couldn't figure out what's wrong. I'm not much of an expert in C programming, and I'm honestly really confused with pointers. Thank you so much for the help, I appreciate it greatly!
Oh, and sorry about the messy code.
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include<stdlib.h>
int x = 0;
int a[];
void swap (int v[], int i, int j) {
int t;
t = v[i];
v[i] = v[j];
v[j] = t;
}
/* recursive function to generate permutations */
int* perm (int v[], int n, int i) {
/* this function generates the permutations of the array
* from element i to element n-1
*/
int j;
/* if we are at the end of the array, we have one permutation
* we can use (here we print it; you could as easily hand the
* array off to some other function that uses it for something
*/
if (i == n) {
for (j=0; j<n; j++){ a[x] = v[j]; x++;} // printf ("%d ", v[j]);
// printf ("\n");
}
else
/* recursively explore the permutations starting
* at index i going through index n-1
*/
for (j=i; j<n; j++) {
/* try the array with i and j switched */
swap (v, i, j);
perm (v, n, i+1);
/* swap them back the way they were */
swap (v, i, j);
}
return a;
}
int fact(int n){
if(n==1){
return 1;
}
else{
return n * fact(n-1);
}
}
int findShortestPath(int **v , int length){
int pathArrayMultiplier = 0;
int ShortestPathLength = 99999;
printf("Called");
int arrayOfVertices[length-1];
for(int i=0 ; i<length-1 ; i++){
arrayOfVertices[i] = i+2;
}
int n = fact(length-1);
bool doBreak = false;
int pathArray[length-1];
//printf(" Called 3");
printf(" %d" , n);
int* Answer;
Answer = malloc(sizeof(int *));
Answer = perm(arrayOfVertices , length-1 , 0);
printf("Called 4");
int j =-1;
for(int i=0 ; i< n*(length-1) ; i++){
doBreak = false;
j++;
printf("%d " , *(Answer + i));
pathArray[j] = *(Answer+i);
if(j == length-2)
{
j = -1;
// Check for negative values. If any value is negative, disregard path
int checklength = *((int *)v + 0 *length + (pathArray[0]-1));
if(checklength < 0){
printf("First check called");
continue;}
for(int i =0 ; i<length-2 ; i++){
if(*((int *)v + (pathArray[i]-1) * length + (pathArray[1 + i]-1)) < 0){
doBreak = true;
printf("Second Check called");
break;}
}
if(doBreak) { pathArrayMultiplier++; continue;}
printf("\n");
int pathLength = *((int *)v + 0 *length + (pathArray[0]-1));
for(int i =0 ; i<length-2 ; i++){
pathLength = pathLength + *((int *)v + (pathArray[i]-1) * length + (pathArray[1 + i]-1));}
printf("Path Length is %d\n" , pathLength);
if(pathLength < ShortestPathLength) { ShortestPathLength = pathLength;}
}
}
printf("\n\n Shortest Path Length is %d \n" , ShortestPathLength);
return ShortestPathLength;
}
int main () {
int len = 5;
printf("Array is initialized");
int v[7][7] = {0,7,-1,10,1,-1,-1,7,0,-1,-1,10 ,-1 ,1,-1,-1,0,10,1,10,-1,10,-1,10, 0,8,-1,-1,-1,10,1,8,0,10,-1,-1,-1,10,-1,10,0,70,-1,1,-1,-1,-1, 70 , 0};
printf("Array is initialized");
int **realArrayPointer = v;
findShortestPath(realArrayPointer, 7);
return 0;
}
Your code is a mess and practically unreadable. However, I took it upon myself as a challenge to see if I could spot your bug. What I saw is that you declare an empty array at the top:
int a[];
and then you write to this array:
a[x] = v[j];
x++;
You never even reset x back to 0, anywhere. So basically, right from the start you are writing to unallocated memory, but the bigger your input set, the more unallocated memory you write to.
There could be other problems with your code. I definitely saw a whole bunch of other things that indicated an incorrect understanding of pointers, but they wouldn't necessarily cause a fatal error. Please at the very least get some kind of auto-indent program to make your code readable.
So.. I have something like this. It is supposed to create arrays with 10, 20, 50 100 .. up to 5000 random numbers that then sorts with Insertion Sort and prints out how many comparisions and swaps were done .. However, I am getting a runtime exception when I reach 200 numbers large array .. "Access violation writing location 0x00B60000." .. Sometimes I don't even reach 200 and stop right after 10 numbers. I have literally no idea.
long *arrayIn;
int *swap_count = (int*)malloc(sizeof(int)), *compare_count = (int*)malloc(sizeof(int));
compare_count = 0;
swap_count = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
compare_count = 0;
swap_count = 0;
free(arrayIn);
}
}
}
EDIT: ok with this free(arrayIn); I get this " Stack cookie instrumentation code detected a stack-based buffer overrun." and I get nowhere. However without it it's "just" "Access violation writing location 0x00780000." but i get up to 200numbers eventually
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
arr[i] = (RAND_MAX + 1)*rand() + rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
I am sure your compiler told you what was wrong.
You are passing a long** to a function that expects a int* at the line
fill_array(&arrayIn, n);
function prototype is
void fill_array(int *arr, int n)
Same problem with the other function. From there, anything can happen.
Always, ALWAYS heed the warnings your compiler gives you.
MAJOR EDIT
First - yes, the name of an array is already a pointer.
Second - declare a function prototype at the start of your code; then the compiler will throw you helpful messages which will help you catch these
Third - if you want to pass the address of a simple variable to a function, there is no need for a malloc; just use the address of the variable.
Fourth - the rand() function returns an integer between 0 and RAND_MAX. The code
a[i] = (RAND_MAX + 1) * rand() + rand();
is a roundabout way of getting
a[i] = rand();
since (RAND_MAX + 1) will overflow and give you zero... If you actually wanted to be able to get a "really big" random number, you would have to do the following:
1) make sure a is a long * (with the correct prototypes etc)
2) convert the numbers before adding / multiplying:
a[i] = (RAND_MAX + 1L) * rand() + rand();
might do it - or maybe you need to do some more casting to (long); I can never remember my order of precedence so I usually would do
a[i] = ((long)(RAND_MAX) + 1L) * (long)rand() + (long)rand();
to be 100% sure.
Putting these and other lessons together, here is an edited version of your code that compiles and runs (I did have to "invent" a print_array) - I have written comments where the code needed changing to work. The last point above (making long random numbers) was not taken into account in this code yet.
#include <stdio.h>
#include <stdlib.h>
// include prototypes - it helps the compiler flag errors:
void fill_array(int *arr, int n);
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count);
void print_array(int *arr, int n, int *swap_count, int *compare_count);
int main(void) {
// change data type to match function
int *arrayIn;
// instead of mallocing, use a fixed location:
int swap_count, compare_count;
// often a good idea to give your pointers a _p name:
int *swap_count_p = &swap_count;
int *compare_count_p = &compare_count;
// the pointer must not be set to zero: it's the CONTENTs that you set to zero
*compare_count_p = 0;
*swap_count_p = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count_p, compare_count_p);
print_array(arrayIn, n, swap_count_p, compare_count_p);
swap_count = 0;
compare_count = 0;
free(arrayIn);
}
}
}
return 0;
}
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
// arr[i] = (RAND_MAX + 1)*rand() + rand(); // causes integer overflow
arr[i] = rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
void print_array(int *a, int n, int* sw, int *cc) {
int ii;
for(ii = 0; ii < n; ii++) {
if(ii%20 == 0) printf("\n");
printf("%d ", a[ii]);
}
printf("\n\nThis took %d swaps and %d comparisons\n\n", *sw, *cc);
}
You are assigning the literal value 0 to some pointers. You are also mixing "pointers" with "address-of-pointers"; &swap_count gives the address of the pointer, not the address of its value.
First off, no need to malloc here:
int *swap_count = (int*)malloc(sizeof(int)) ..
Just make an integer:
int swap_coint;
Then you don't need to do
swap_coint = 0;
to this pointer (which causes your errors). Doing so on a regular int variable is, of course, just fine.
(With the above fixed, &swap_count ought to work, so don't change that as well.)
As I told in the comments, you are passing the addresses of pointers, which point to an actual value.
With the ampersand prefix (&) you are passing the address of something.
You only use this when you pass a primitive type.
E.g. filling the array by passing an int. But you are passing pointers, so no need to use ampersand.
What's actually happening is that you are looking in the address space of the pointer, not the actual value the pointer points to in the end. This causes various memory conflicts.
Remove all & where you are inputting pointers these lines:
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
So it becomes:
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count, compare_count);
print_array(arrayIn, n, swap_count, compare_count);
I also note that you alloc memory for primitive types, which could be done way simpler:
int compare_count = 0;
int swap_count = 0;
But if you choose to use the last block of code, DO use &swap_count and &compare_count since you are passing primitive types, not pointers!
I cannot understand why i is set to 0 right after array is initialized to zero.
The program is working fine because I have reinitialized value of k to i.
But I could not find out why i becomes 0.
And why memset() is clearing the array, or setting the array to 0?
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
long long int i = 123456789;
long long int j = 987654321;
long long int cnt = 0;
int array[9] ;
int xyz, k, x, rem, se;
xyz = 0;
// printf("I = %llf", i);
for (i; (i < j) && (cnt < 100000); i++)
{
k = i;
x = 0;
for (se = 0; se <= 9; se++)
{
array[se] = 0;
}
/*************************************************/
i = k; // Here i becomes zero. Why?
/************************************************/
//memset(array, 0, 9);
while(k != 0)
{
rem = k % 10;
for(se = 0; se <= 9; se++)
{
if(rem == array[se])
{
xyz = 1;
break;
}
}
if(rem == array[se])
{
xyz = 1;
break;
}
array[x++] = rem;
k = k / 10;
}
if (xyz != 1)
{
cnt++;
// printf("Cnt = %d ", cnt);
// printf("The value i is = %lld\n", i);
// Sleep(10);
}
xyz = 0;
// printf("The value i is = %lld\n", i);
// printf("Cnt = %d \n", cnt);
fflush(stdin);
}
printf("The value i is = %lld \n", i-1);
return 0;
}
You have a buffer overflow; since the buffer is on the stack, it might be regarded as a form of Stack Overflow†.
int array[9]; // Elements array[0] .. array[8]
...
for (se = 0; se <= 9; se++)
{
array[se] = 0;
}
It must be k that is being overwritten with the extra 0; i is assigned 0 because that's the value in k. You invoke 'undefined behaviour' when you write outside the boundaries of an array, as you did here. Undefined behaviour means that anything can happen and it is OK. Sometimes, it will seem to work; sometimes, there'll be unexpected side effects. Avoid 'undefined behaviour' at all costs.
The idiomatic for loop is:
for (se = 0; se < 9; se++)
array[se] = 0;
Note the < instead of <=.
† There are those who would disagree. See the comments.
You also ask about the (commented out) call to memset():
//memset(array, 0, 9);
The third parameter to memset() is the size in bytes of the area of memory to be set. You are setting 9 bytes out of a total of (probably) 36 in the array, which is unlikely to be what you wanted.
Here, the array is defined in the same function so it is safe and sensible to write:
memset(array, 0, sizeof(array));
If array was a parameter passed to a function, that would not work correctly; you would need a different size. For example:
void somefunc(int array[], int num)
{
...
memset(array, 0, num * sizeof(array[0]));
...
}
You are overwriting the end of the array.
int array[9] ;
for(se = 0; se <= 9; se++)
{
array[se] = 0;
}
In C, arrays are indexed from 0, so the loop goes one step to far. The idiomatic syntax is:
for(se = 0; se < 9; se++)
In other words, use < with the number of elements as the value. Often written to remove the scary numerical constant, like so:
for(se = 0; se < sizeof array / sizeof *array; se++)
This uses the sizeof operator to automatically (at compile-time) compute the proper number of elements, so that if you change the array definition the loop remains correct.
One way to check this is to check the pointer of x and array[9] by printing &x and &array[9].
If they are same, you are surely overwriting as mentioned.