Weird behaviour of function with malloc() and realloc() resulting in Segmentation Fault - c

I have a function named num_to_binary, which is used to convert a decimal number stored in the form of array. The prototype for this function num_to_binary is as below:
void num_to_binary(int *number_b, int size_of_number);
Here:
number_b is pointer to array which stores my number. For example, if I would like to convert the number 12345 to binary, then I will be storing 12345 in number_b as follows:
number_b[0] = 1
number_b[1] = 2
number_b[2] = 3
number_b[3] = 4
number_b[4] = 5
Also, size_of_number is the number of digits in the number (or it is the number of elements in the array number_b). So for the number 12345, size_of_number has the value 5.
Below is the full declaration of the function num_to_binary:
void num_to_binary(int *number_b, int size_of_number)
{
int *tmp_pointer = malloc(1 * sizeof(int));
int curr_size = 1;
int i = 0;
while(!is_zero(number_b,size_of_number))
{
if(i != 0)
{
curr_size += 1;
tmp_pointer = realloc(tmp_pointer, curr_size * sizeof(int));
}
if(number_b[size_of_number - 1] % 2 == 1)
{
tmp_pointer[i] = 1;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
else
{
tmp_pointer[i] = 0;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
}
int *fin_ans;
fin_ans = malloc(curr_size * sizeof(int));
for(int j = 0 ; j < curr_size; j++)
{
fin_ans[curr_size-1-j] = tmp_pointer[j];
}
}
In the above function:
tmp_pointer: It is initially allocated some memory using malloc(), and is used to store the reverse of the binary representation of the number stored in number_b
curr_size: It stores the current size of tmp_pointer. It is initially set to 1.
i: It is used to keep track of the while loop. It is also used to reallocation purpose, which I have explained a bit later.
is_zero(number_b, size_of_number): It is a function, which returns 1 if the number stored in number_b is 0, else it returns 1.
divide_by_2(number_b, size_of_number): It divides the number stored in number_b by 2. It does NOT change the size of the array number_b.
fin_ans: It is an integer pointer. Since the binary representation stored in the array tmp_pointer will be the reverse of the actual binary representation of the number, so fin_ans will store the correct binary representation of number by reversing the content of tmp_pointer.
Below is the how this function works :
First of all, tmp_pointer is allocated a memory equal to the
size of 1 int. So, now tmp_pointer can store an integer.
We now go into the while loop. The loop will terminate only
when the number stored in number_b equals 0.
Now, we check if i is equal to 0 or not. If it is not equal to
zero, then this means than the loops has been run atleast once, and
in order to store the next binary digit, we resize the memory
allocated to tmp_pointer so that it can store the next bit.
If the last digit of the number is odd, then that implies that the
corresponding binary digit will be 1, else it will be 0. The
if and else condition do this task. They also increment
i each time one of them is executed, and also divide the number by 2.
Now, we are out of the loop. It's time to reverse the binary number
stored in tmp_pointer to get the final answer.
For this, we create a new pointer called fin_ans, and allocate
it the memory which will be used for storing the correct binary
representation of the number.
The last for loop is used to reverse the binary representation
and store the correct binary representation in fin_ans.
The problem:
The code runs for small numbers such as 123, but for large numbers such as 1234567891, it gives a segmentation fault error. This can be checked by trying to print the digits stored in fin_ans.
I tried using GDB Debugger, and got to know that the reason for Segmentation Fault lies in the while loop. I am sure that the functions divide_by_2 and is_zero are not the reason for Segmentation Fault, since I have tested them thoroughly.
I also used DrMemory, which indicated that I am trying to access (read or write) a memory location which has not been allocated. Unfortunately, I am not able to figure out where the error lies.
I suspect realloc() to be the cause of Segmentation Fault, but I am not sure.
Apologies for such a long question, however, I would highly appreciate any help provided to me for this code.
Thanks in advance for helping me out !

There are multiple problems in the code:
you do not check for memory allocation failure
you forget to free tmp_pointer before leaving the function.
you allocate a new array fin_ans to reserve the array tmp_pointer and perform the reverse operation but you do not return this array to the caller, nor do you have a way to return its size. You should change the prototype to return this information.
if the number of zero, the converted number should probably have 1 digit initialized as 0, but you use malloc which does not initialize the array it allocates so tmp_pointer[0] is uninitialized.
you did not provide the code for is_zero() nor divide_by_two(). It is possible that bugs in these functions cause the segmentation fault, especially if the loop does not reach zero and memory is eventually exhausted during this infinite loop.
Here is a modified version:
int *num_to_binary(int *number_b, int size_of_number, int *binary_size) {
int i, j, curr_size;
int *p, *newp;
curr_size = 1;
p = malloc(1 * sizeof(int));
if (p == NULL)
return NULL;
p[0] = 0;
for (i = 0; !is_zero(number_b, size_of_number); i++) {
if (i != 0) {
curr_size += 1;
newp = realloc(p, curr_size * sizeof(int));
if (newp == NULL) {
free(p);
return NULL;
}
p = newp;
}
p[i] = number_b[size_of_number - 1] % 2;
divide_by_2(number_b, size_of_number);
}
for (i = 0, j = curr_size; i < j; i++)
int digit = p[--j];
p[j] = p[i];
p[i] = digit;
}
*binary_size = curr_size;
return p;
}

There is no need for multiple memory reallocations. Result memory buffer size could be easily evaluated as binary logarithm of the decimal input value. Calculation of the number binary representation could also be simplified:
//Transform binary array to actual number
int arr2int(int* pIntArray, unsigned int nSizeIn) {
if (!pIntArray || !nSizeIn)
return 0;
int nResult = 0;
for (unsigned int i = 0; i < nSizeIn; ++i)
nResult += pIntArray[i] * (int)pow(10, nSizeIn - i - 1);
return nResult;
}
int* int2bin(int* pIntArray, unsigned int nSizeIn, unsigned int* nSizeOut){
//0) Converting int array to the actual value
int nVal = arr2int(pIntArray, nSizeIn);
//1)Evaluating size of result array and allocating memory
if(!nVal)
*nSizeOut = 1;
else
*nSizeOut = (int)floor(log2(nVal)) + 1;
//2)Allocate and init memory
int* pResult = malloc(*nSizeOut);
memset(pResult, 0, *nSizeOut * sizeof(int));
//3) Evaluate binary representation
for (unsigned int i = 0; i < *nSizeOut; ++i){
int nBinDigit = (int)pow(2, i);
if (nBinDigit == (nVal & nBinDigit))
pResult[*nSizeOut - i - 1] = 1;
}
return pResult;
}
Testing:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define _DC 9
int main()
{
int test[_DC];
for (int i = 0; i < _DC; ++i)
test[i] = i;
unsigned int nRes = 0;
int* pRes = int2bin(test, _DC, &nRes);
for (unsigned int i = 0; i < nRes; ++i)
printf("%d", pRes[i]);
free(pRes);
return 0;
}

Related

Nth Fibonacci using pointers in C; recursive and array

I have this code so far. It works and does what I want it to. I'm wondering if I could make it better. I do not really care for user input or any other "finish touches," just want to make the code more efficient and maybe more useful for future projects.
Excessive comments are for my personal use, I find it easier to read when I go back to old projects for references and what not.
Thanks!
#include<stdio.h>
#include<stdlib.h>
void fabonacci(int * fibArr,int numberOfSeries){
int n;
//allocate memory size
fibArr = malloc (sizeof(int) * numberOfSeries);
//first val, fib = 0
*fibArr = 0;//100
fibArr++;
//second val, fib = 1
*fibArr = 1;//104
fibArr++;
//printing first two fib values 0 and 1
printf("%i\n%i\n", *(fibArr- 2),*(fibArr- 1));
//loop for fib arr
for(n=0;n<numberOfSeries -2;n++,fibArr++){
//108 looking back at 104 looking back at 100
//112 looking back at 108 looking back at 104
*fibArr = *(fibArr-1) + *(fibArr -2);
//printing fib arr
printf("%i\n", *fibArr);
}
}
int main(){
//can implm user input if want
int n = 10;
int *fib;
//calling
fabonacci(fib,n);
}
Your code is halfway between two possible interpretations and I can't tell which one you meant. If you want fibonacci(n) to just give the nth number and not have any external side effects, you should write it as follows:
int fibonacci(int n) {
int lo, hi;
lo = 0;
hi = 1;
while(n-- > 0) {
int tmp = hi;
lo = hi;
hi = lo + tmp;
}
return lo;
}
You need no mallocs or frees because this takes constant, stack-allocated space.
If you want, instead, to store the entire sequence in memory as you compute it, you may as well require that the memory already be allocated, because this allows the caller to control where the numbers go.
// n < 0 => undefined behavior
// not enough space allocated for (n + 1) ints in res => undefined behavior
void fibonacci(int *res, int n) {
res[0] = 0;
if(n == 0) { return; }
res[1] = 1;
if(n == 1) { return; }
for(int i = 2; i <= n; i++) {
res[i] = res[i-1] + res[i-2];
}
}
It is now the caller's job to allocate memory:
int main(){
int fib[10]; // room for F_0 to F_9
fibonacci(fib, 9); // fill up to F_9
int n = ...; // some unknown number
int *fib2 = malloc(sizeof(int) * (n + 2)); // room for (n + 2) values
if(fib2 == NULL) { /* error handling */ }
fibonacci(fib2 + 1, n); // leave 1 space at the start for other purposes.
// e.g. you may want to store the length into the first element
fib2[0] = n + 1;
// this fibonacci is more flexible than before
// remember to free it
free(fib2);
}
And you can wrap this to allocate space itself while still leaving the more flexible version around:
int *fibonacci_alloc(int n) {
int *fib = malloc(sizeof(int) * (n + 1));
if(fib == NULL) { return NULL; }
fibonacci(fib, n);
return fib;
}
One way to improve the code is to let the caller create the array, and pass the array to the fibonacci function. That eliminates the need for fibonacci to allocate memory. Note that the caller can allocate/free if desired, or the caller can just declare an array.
The other improvement is to use array notation inside of the fibonacci function. You may be thinking that the pointer solution has better performance. It doesn't matter. The maximum value for n is 47 before you overflow a 32-bit int, so n is not nearly big enough for performance to be a consideration.
Finally, the fibonacci function should protect itself from bad values of n. For example, if n is 1, then the function should put a 0 in the first array entry, and not touch any other entries.
#include <stdio.h>
void fibonacci(int *array, int length)
{
if (length > 0)
array[0] = 0;
if (length > 1)
array[1] = 1;
for (int i = 2; i < length; i++)
array[i] = array[i-1] + array[i-2];
}
int main(void)
{
int fib[47];
int n = sizeof(fib) / sizeof(fib[0]);
fibonacci(fib, n);
for (int i = 0; i < n; i++)
printf("fib[%d] = %d\n", i, fib[i]);
}

Why does my sieve get SIGSEGV

Alright, so, just for fun, I was working on the sieve of eratosthenes.
It was working fine intially so I sought out to improve its runtime complexity. and now, I on't know why, but I'm gettig a segmentation fault.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* check = malloc(1000000000 * sizeof(int));
long long int i;
for(i = 0;i < 1000000000;i++)
{
check[i] = 0;
}
int j = 0;
for(i = 2;i <= 1000000002;i++)
{
if(check[i] == 0)
{
printf("%lld\n", i);
for(j = 1;j < (1000000001/i);j++)
{
check[j*i] == 1;
}
}
}
return 0;
}
Any help as to why it fails would be appreciated.
Your code has multiple errors, any of which could explain a segfault. First, you have not checked the return value of malloc, which may be NULL, even when you are totally sure it couldn't be.
Second, you are exceeding the bounds of the array you've allocated when you iterate i from 2 to 1000000002. With so many zeros it's hard to eyeball, so here are your figures with separators:
Initial allocation: 1,000,000,000
Range of i: 2 to 1,000,000,002 inclusive
At the end of that loop you are accessing memory past the end of your array.
#include <stdio.h>
#include <stdlib.h>
#if 1
static const size_t N = 1000 * 1000 * 1000;
#else
static const size_t N = 1000;
#endif
Don't use a magic number, define it as a constant. 1000000000 is also hard to read. Your C compiler can do calculation for you before it emits an executable. And you should have started with a small number. If you change #if 1 into #if 0, then the #else clause defining N as 1,000 will take effect.
int main(void)
{
char* check = malloc(N + 3);
When you essentially use check as a boolean array, it doesn't have to be of type int. int occupies 4 bytes whereas char only 1 byte.
if (NULL == check) {
perror("malloc");
abort();
}
malloc silently returns NULL when it failed to find a memory chunk of the specified length. But if you work with 64 bit OS and compiler, I don't think it's likely to fail...
long long int i;
memset(check, 0, sizeof(check[0]) * (N + 3));
memset fills an array with the value of the 2nd parameter (here 0.) The third parameter takes the number of BYTES of the input array, so I used sizeof(check[0]) (this is not necessary for a char array becuase sizeof(char)==1 but I always stick to this practice.)
int j = 0;
for(i = 2;i <= N+2;i++)
{
if(check[i] == 0)
{
printf("%lld\n", i);
for(j = 1;j < ((N+1)/i);j++)
{
check[j*i] = 1;
You wrote check[j*i] == 1 but it was an equality test whose result didn't have any effects.
}
}
}
free(check);
It is a good practice to always free the memory chunk that you allocated with malloc, regardless whether free is necessary or not (in this case no, because your program just exits at the end of sieve calculation.) Perhaps until you become really fluent with C.
return 0;
}

Segmentation Fault 11 with recursive function in C

I keep receiving a Segmentation Fault 11 for the following code. I believe it has something to do with recursion but I'm not entirely sure how. The method should take in an array, skip the odd values, and keep repeating until it has an array with only value left and returns that value.
Thanks!
#include <stdio.h>
int callTable(int table[], int size)
{
int i = 0;
int j = 0;
int cHeight = size / 2;
int cTable[cHeight];
while (i < size)
{
if (table[i] % 2 == 0)
{
cTable[j] = table[i];
j++;
}
i++;
}
if (size > 1)
return callTable(cTable, cHeight);
else
return cTable[0];
}
int main()
{
int tPass[100];
int i, answer;
for (i = 0; i < 100; i++)
tPass[i] = i + 1;
answer = callTable(tPass, sizeof(tPass) / sizeof(tPass[0]));
printf("%d\n", answer);
}
Do you want to skip the odd values or the odd indexes? You are currently skipping the odd values, so after you call callTable once, there are only even values left. Then, on the second call, you try to use an array of half the size to store the even values (which are all of them), so you try to store the entire array on another with half the size.
If you intended to skip the odd indexes, then change this line:
if (table[i]%2==0)
for this one:
if (i%2==0)
That runs fine and returns 1 (which is the number with index 0).

Segmentation fault for prime generator

I am working on a small piece of code that generates all the primes between two numbers for a set. I decided to use a sieve (and i know theres probably a much more efficient way to do what I want than the way my code is using it) and for some reason I am getting a SIGSEGV (segmentation fault). I have looked over it quite a bit and I don't know what's wrong. I haven't been able to reproduce the error on my local machine. I get this error generally occurs when accessing out of bounds, but I don't know if thats the case here. Be Gentle, I am pretty new to C, always stuck to the higher level stuff.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char argv){
int numberOfSets;
scanf("%d", &numberOfSets);
int i;
int lowerBound, upperBound;
for(i=0; i < numberOfSets; i++){
scanf("%d %d", &lowerBound, &upperBound);
//allocating memory and initializing to Zero
int (*sieve) = malloc(sizeof(int) * (upperBound+1));
memset(sieve, 0, (sizeof(int) * (upperBound+1)));
//iterating through sieve for even numbers and marking them as non prime
int counter = 2;
if(sieve[counter] == 0)
sieve[counter] = 1;
int multiplier = 2;
int multiple = counter * multiplier;
while(multiple <= upperBound){
sieve[multiple] = -1;
multiplier++;
multiple = multiplier * counter;
}
//iterating through sieve (incrementing by two) and filling in primes up to upper limit
counter = 3;
while( counter <= upperBound){
if(sieve[counter] == 0)
sieve[counter] = 1;
multiplier = 2;
multiple = counter * multiplier;
while(multiple < upperBound){
sieve[multiple] = -1;
multiplier++;
multiple = multiplier * counter;
}
counter = counter + 2;
}
int newCount = lowerBound;
//check and print which numbers in the range are prime
while (newCount <= upperBound){
if(sieve[newCount] == 1)
printf("%d\n", newCount);
newCount=newCount+1;
}
//free the allocated memort
free(sieve);
}
}
The problem was that I was not checking the result of Malloc. I was attempting to allocate an array that was to large and the allocation was failing. This left the array I was assigning to null and thus I was accessing out of its bounds.

Converting int to int[] in 'C'

I basically want to convert a given int number and store individual digits in an array for further processing.
I know I can use % and get each digit and store it. But the thing is if I do not know the number of digits of the int till runtime and hence I cannot allocate the size of the array. So, I cannot work backwards (from the units place).
I also do not want to first store the number backwords in an array and then again reverse the array.
Is there any other way of getting about doing this?
Eg: int num = 12345;
OUTPUT: ar[0] = 1, ar[1] = 2 and so on, where ar[] is an int array.
Convert is probably not the right word. You can take the int, dynamically allocate a new int[], and then store the digits of the int into the int[]. I'm using log base 10 to calculate how many digits num has. Include math.h to use it. The following code is untested, but will give you an idea of what to do.
int num = 12345;
int size = (int)(log10(num)+1);
// allocate array
int *digits = (int*)malloc(sizeof(int) * size);
// get digits
for(int i=size-1; i>=0; --i) {
digits[i] = num%10;
num=num/10; // integer division
}
The easiest way is to calculate number of digits to know the size of an array you need
int input = <input number>; // >= 0
int d, numdigits = 1;
int *arr;
d = input;
while (d /= 10)
numdigits++;
arr = malloc(sizeof(int) * numdigits);
There's even easier way: probably you pass a number to your program as an argument from command line. In this case you receive it as a string in argp[N], so you can just call strlen(argp[N]) to determine number of digits in your number.
If you have a 32-bit integer type, the maximum value will be comprised of 10 digits at the most (excluding the sign for negative numbers). That could be your upper limit.
If you need to dynamically determine the minimum sufficient size, you can determine that with normal comparisons (since calling a logarithmic function is probably more expensive, but a possibility):
size = 10;
if (myint < 1000000000) size--;
if (myint < 100000000) size--;
/* ... */
Declaring the array to be of a dynamic size depends on the C language standard you are using. In C89 dynamic array sizes (based on values calculated during run-time) is not possible. You may need to use dynamically allocated memory.
HTH,
Johan
The following complete program shows one way to do this. It uses unsigned integers so as to not have to worry about converting - you didn't state what should happen for negative numbers so, like any good consultant, I made the problem disappear for my own convenience :-)
It basically works out the required size of an array and allocates it. The array itself has one element at the start specifying how many elements are in the array (a length int).
Each subsequent element is a digit in sequence. The main code below shows how to process it.
If it can't create the array, it'll just give you back NULL - you should also remember to free the memory passed back once you're done with it.
#include <stdio.h>
#include <stdlib.h>
int *convert (unsigned int num) {
unsigned int *ptr;
unsigned int digits = 0;
unsigned int temp = num;
// Figure out how many digits in the number.
if (temp == 0) {
digits = 1;
} else {
while (temp > 0) {
temp /= 10;
digits++;
}
}
// Allocate enough memory for length and digits.
ptr = malloc ((digits + 1) * sizeof (unsigned int));
// Populate array if we got one.
if (ptr != NULL) {
ptr[0] = digits;
for (temp = 0; temp < digits; temp++) {
ptr[digits - temp] = num % 10;
num /= 10;
}
}
return ptr;
}
That convert function above is the "meat" - it allocates an integer array to place the length (index 0) and digits (indexes 1 through N where N is the number of digits). The following was the test program I used.
int main (void) {
int i;
unsigned int num = 12345;
unsigned int *arr = convert (num);
if (arr == NULL) {
printf ("No memory\n");
} else {
// Length is index 0, rest are digits.
for (i = 1; i <= arr[0]; i++)
printf ("arr[%d] = %u\n", i, arr[i]);
free (arr);
}
return 0;
}
The output of this is:
arr[1] = 1
arr[2] = 2
arr[3] = 3
arr[4] = 4
arr[5] = 5
You can find out the number of digits by taking the base-10 logarithm and adding one. For that, you could use the log10 or log10f functions from the standard math library. This may be a bit slower, but it's probably the most exact as long as double has enough bits to exactly represent your number:
int numdigits = 1 + log10(num);
Alternatively, you could repeatedly divide by ten until the result is zero and count the digits that way.
Still another option is just to allocate enough room for the maximum number of digits the type can have. For a 32-bit integer, that'd be 10; for 64-bit, 20 should be enough. You can just zero the extra digits. Since that's not a lot of wasted space even in the worst case, it might be the simplest and fastest option. You'd have to know how many bits are in an int in your setup, though.
You can also estimate fairly well by allocating 3 digits for each 10 bits used, plus one. That should be enough digits unless the number of bits is ridiculously large (way above the number of digits any of the usual int types could have).
int numdigits = 1
unsigned int n = num;
for (n = num; n & 0x03ff; n >>= 10)
numdigits += 3;
/* numdigits is at least the needed number of digits, maybe up to 3 more */
This last one won't work (directly) if the number is negative.
What you basically want to do is to transform your integer to an array of its decimal positions. The printf family of functions perfectly knows how to do this, no need to reinvent the wheel. I am changing the assignment a bit since you didn't say anything about signs, and it simply makes more sense for unsigned values.
unsigned* res = 0;
size_t len = 0;
{
/* temporary array, large enough to hold the representation of any unsigned */
char positions[20] = { 0 };
sprintf(position, "%u", number);
len = strlen(position);
res = malloc(sizeof(unsigned[len]));
for (size_t i = 0; i < len; ++i)
res[i] = position[i] - '0';
}

Resources