I have a problem in the code. malloc works and in the while-loop, realloc() works for the first time and when it is called the second time it always fails.
The code is part of an algorithm to get the prime factors of a number.
int main()
{
int n, in, *ar, len = 0;
scanf("%d", &n);
ar = (int *) malloc(1 * sizeof(int));
while(n % 2 == 0){
ar[len] = 2;
len++;
ar = (int *) realloc(ar, len * sizeof(int));
if(ar == NULL){
printf("Error");
return 1;
}
n /= 2;
}
return 0;
}
I tried with len initialized to 1 but it still fails. It is strange it does not fail on the first call but it fails on the second call. I have read other similar questions but I am a beginner and I didn`t understand.
Thanks in advance!
Here in your program, you are accessing an array out of bounds. which leads to undefined behaviour.
initially, when len = 0, in the while loop:
ar[len] = 2; //ar[0] = 2;
len++; //len = 1
ar = (int *) realloc(ar, len * sizeof(int));
//ar is of size 1
then in next iteration, when len = 1
ar[1] = 2; //you cannot access ar[1] as size of `ar` is only 1.
this continues with each iteration. To avoid this do:
//initialize len to 1
int len = 1;
and use ar[len-1] instead of ar[len] in the while loop.
Have a look at this: How dangerous is it to access an array out of bounds?
Related
I am new to C, and I am trying to solve a coding excercise to practice.
In this particular method, I recevive as parameter a char** swhich always contains 5 strings which I have to process and convert into just one, that is the return value of the method.
Given that there is no way to know how long the final string will be, my idea was to use realloc once I knew the length of each particular string in the array. However, even though it works for a couple of times, after some iterations (In a test case I run, for example it works until size = 43), it suddenly fails with realloc(): invalid next size.
I've searched all around and could not figure out what is that I am doing wrong. Could you please help me figure it out?
char* process(char** s) {
size_t size = 0, last = 0;
char *result, *word, c;
char *temp = NULL;
result = malloc(1);
for (size_t i = 0; i < 5; i++)
{
word = s[i];
size += strlen(word);
temp = realloc(result, size + 1);
if (!temp){
printf("Failed Reallocating");
free(result);
exit(-1);
}
else result = temp;
for (size_t j = last; j < last + size; j++)
{
c = word[j - last];
result[j] = isalpha(c) ? change_char(c) : c;
}
last += strlen(word);
}
result[size] = '\0';
return result;
}
You are writing past the memory size you (re)allocated.
temp = realloc(result, size + 1); means you allocated size+1 chars.
but in the inner loop for (size_t j = last; j < last + size; j++) the j goes all the way to last+size-1 which is guaranteed to be past size+1 and then you write result[j] = isalpha(c) ? change_char(c) : c; so you write past the memory you allocated, overwriting other data, including the meta-data realloc uses to keep track of what is allocated and what is free. Thus it will fail with an almost random error the next time you attempt to reallocate.
The fix is very simple, however. Iterate just up to the new size you allocated, for (size_t j = last; j < size; j++) and it will all work as expected.
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.
If I have int **array and want to place a series of numbers in it (I don't know its size), 5 3 4 0 or 9 1 5 8 3 0 as an example. As far as I know I should be using malloc
So I did something like this
int **array;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
array = (int**)malloc(sizeof(int*)*(inp+1)); //since inp start at 0
array[inp] = &n; //is this even correct?
inp++;
}
My first question is: Will this method (the loop) upgrade/expand the size of the array or is what I am doing a waste of memory?
The second question is how can I print/edit the values of this array?
EDIT:
From your answers I have came up with the following.
int **array;
int n = 1, inp = 0;
array = (int**)malloc(sizeof(int*));
while(n){
scanf("%d", &n);
realloc( array, sizeof((int*)(inp+1)));
array[inp] = n;
inp++;
}
Is this the correct way to do it?
Note* I am aware that it does not have to be a pointer of a pointer, but I need it to be for something else later on.
You code is wrong for at least these reasons.
1) You keep doing malloc to array and thereby loose previously malloced blocks. The function to use is realloc when extending the size of dynamic memory.
2) You store the address of n instead of the value of n
Besides that it seems strange to use a double pointer. Why not do like:
int *array = NULL;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
array = realloc(array, sizeof(int)*(inp+1));
array[inp] = n;
inp++;
}
EDIT after OPs update
If you really want to use a double pointer (i.e. int **array;), you need to allocate memory in two levels.
That could look like:
int **array = malloc(sizeof *array);
*array = NULL;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
*array = realloc(*array, sizeof(int)*(inp+1));
(*array)[inp] = n;
inp++;
}
What you're doing in your code is allocating progressively larger areas of memory and saving the input value in the last position of each new area, while losing the pointers to the previously allocated areas. A commom and efficient solution for what you want (which is used in C++'s vectors, I believe) is to allocate some minimum amount of space, then check at each iteration if you are on the verge of exceeding it. In case you are, reallocate the area doubling the space. Something like this:
int i = 0; //iterator
int s = 1; //array size
int n; //input (use do-while so you don't have to worry about initial value)
//it doesn't have to be bidimensional for a single series
int * array = (int *) malloc(sizeof(int) * s);
do
{
if(i == s)
{
s *= 2;
array = (int *) realloc(array, sizeof(int) * s);
}
scanf("%d", &n);
array[i++] = n; //assign with the value, not with the address
}
while(n)
UPDATE: if you really need to use **int, do it like this:
int n, i = 0, s = 1;
int ** array = (int **) malloc(sizeof(int*) * s);
do
{
if(i == s)
{
s *= 2;
array = (int **) realloc(array, sizeof(int *) * s);
}
scanf("%d", &n);
array[i] = (int *) malloc(sizeof(int));
array[i][0] = n;
++i;
}
while(n)
For example:
[1,2,3] -> [2,4,6]
[9,1] -> [1,8,2]
[6,7,5] -> [1,3,5,0]
I got this question on my first tech interview yesterday (did it in C because that's my best language, so a C answer would be help more) and completely blanked :(
This is what I was thinking:
Start at the end of the array and keeping moving left
At every arr[i], multiply by 2 and see if there're 2 digits (if arr[i]/10 != 0) and if there is a left most digit, carry it over to arr[i-1] as long as a[i-1] != NULL.
I just could not figure out how to actually do this in C. I had something like:
int* multTwo(int* arr, int len) {
int *newarr; // I know i have to malloc, but not sure what size because
// wouldnt the size depend on the new number's size?
int temp, i;
for (i=len-1; i>=0; i--) {
temp = arr[i]*2;
newarr[i] = temp%2;
if(temp/10 != 0)
newarr[i-1] = temp/2;
}
return newarr;
}
But there are a lot of bugs in my code. Is there a better way or am I on the right track?
Some pseudo code. The main idea is to show the depth of C knowledge as part of the interview, not Code golf.
What signature?
// arr is not changed, use `const`
// array indexing best done with `size_t`
int* multTwo(const int* arr, size_t len) {
Size needed and show error handling. Maybe also detect arr == NULL when len > 0
need = len;
// if lead element is 5 or more, add 1.
// Error if element is not in 0-9 range
Allocate memory. Allocating to size of variable de-referenced type is less error prone, easier to review and maintain than coding the variable type. Showing maintenance concerns during a C interview is a good thing. Think if later code changed to unsigned char* multTwo(const unsigned char* arr, size_t len) {, no need to change newarr = malloc(sizeof *newarr * need).
newarr = malloc(sizeof *newarr * need)
Check allocation. An allocation of 0 is OK to return NULL. Yet maybe this routine should still allocate 1 byte, a tad wasteful, to insure a NULL return is an error. Discussing issues like with the interviewer is good. Shows you want to clearly understand the customer's need not just in the meat of the function, but the corner cases.
if (newarr == NULL && need > 0) fail()
Loop though and populate the new array much like OP coded with meaningful variable names and using unsigned array indexing.
size_t arr_i=len;
size_t newarr_i=need;
int carry = 0;
while (arr_i > 0)
sum = arr[--arr_i]*2 + carry;
newarr[--newarr_i] = sum%10;
carry = sum/10;
}
if (carry) {
newarr[--newarr_i] = carry;
}
Return newarr
Best I can think in a short time, like an interview
#include <stdio.h>
#include <stdlib.h>
void invert (int *head, int *tail)
{
int temp;
if (head < tail)
{
temp = *head;
*head = *tail;
*tail = temp;
invert(++head, --tail);
}
}
int* multTwo(int* arr, size_t len)
{
int value = 0;
int n_digits =0 ;
// CONVERT THE ARRAY TO NUMBER
while(len--)
{
value += *arr;
value *=10;
arr++;
}
value /= 10;
// DOUBLE THE NUMBER
value *= 2;
// CONVERT IT TO BUFFER
int *digits = malloc(sizeof(*digits));
while ((value>0) && (digits != NULL))
{
digits[n_digits++] = value%10;
value /= 10;
digits = realloc( digits, sizeof(*digits) * (n_digits+1) );
}
if (digits != NULL)
{
invert(digits, &digits[n_digits-1]);
printf("[ ");
for (int i=0; i<n_digits; i++)
printf("%d, ", digits[i]);
printf("]\n");
}
return digits;
}
int main(void)
{
int array[] = {6,7,5};
multTwo(array, sizeof(array)/sizeof(array[0]));
return 0;
}
I would start by looking to see if either the first digit in arr is 5 or more to check if the newarr array needs to be 1 larger than the original array.
So something like this for initialization:
int* newarr;
int newlen;
if (*arr >= 5)
newlen = len + 1;
else
newlen = len;
newarr = (int*)malloc(sizeof(int) * newlen);
memset(newarr, 0, newlen); //initialize all newarr values to 0
Now obviously we have to do our multiplication now. To get the 1's digit we do use the modulo operator %, and to get the 10's digit we use the division operator /. Of course we only need to do the division if our multiplied value is 10 or greater. So our loop to populate newarr will look something like this:
int i, temp;
for (i = 1; i <= len; i++) {
temp = *(arr + i - 1) * 2;
if (temp < 10) {
*(newarr + i - 1) += temp;
}
else {
*(newarr + i - 1) += temp / 10; //inset 10's digit
*(newarr + i) += temp % 10; //inset 1's digit
}
}
So our full function ends up being
#include <stdlib.h>
#include <string.h>
int* multTwo(int* arr, int len)
{
int* newarr;
int newlen;
if (*arr >= 5)
newlen = len + 1;
else
newlen = len;
newarr = (int*)malloc(sizeof(int) * newlen);
memset(newarr, 0, newlen); //initialize all newarr values to 0
int i, temp;
for (i = 1; i <= len; i++) {
temp = *(arr + i - 1) * 2;
if (temp < 10) {
*(newarr + i - 1) += temp;
}
else {
*(newarr + i - 1) += temp / 10; //insert 10's digit
*(newarr + i) += temp % 10; //inset 1's digit
}
}
return newarr; //don't forget to free once you're done with newarr!
}
I'm trying to write a code that can check whether a dynamic array is sorted, but I get an error. The code has to be recursive.
When I input an unsorted array there seems to be no problem, but when I input a sorted array the program halts abruptly with:
Process return -1073741571
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int ordenado(int*);
int main() {
int i = 0, res = 0;
int*arr = NULL;
arr = (int*) malloc(sizeof (int));
while (arr[i] != 0) {
i++;
arr = (int*) realloc(arr, (i + 1) * sizeof (int));
scanf("%d", &arr[i]);
}
res = ordenado(arr);
printf("\n%d ", res);
return 0;
}
int ordenado(int* arr) {
if (arr[0] == 0) {
return 1;
}
if (arr[0] <= arr[1]) {
return ordenado(arr++);
}
else return 0;
}
Sorry my first answer was not right. I corrected below.
Explanation
I added scanf("%d", &arr[i]); before the loop to fill arr[0]
I changed the ordenado function
When you hit 0 then return 1
When you hit x but the next element is 0 then return 1 (Note the || is a short circuit. If you don't hit 0 then there is a next element. So you can check it for 0 here too.)
As soon as two numbers are not in order return 0 (I think that's faster)
Otherwise there is a next element that is not 0 and call ordenado(++arr) (prefix, not postfix)
Note about prefix and postfix:
The difference between prefix and postfix in many programming languages it the execution order. Assume i and j being 0 before execution in both statements.
i += ++j;
The above code is equivalent to this
j = j + 1;
i = i + j;
While the below code
i += j++;
is equivalent to this
i = i + j;
j = j + 1;
I.e. in prefix the increment takes place before the expression is evaluated, while in postfix the increment takes place after the expression is evaluated. This usually holds true not matter the data type (i.e. includes pointer).
Your line of code
return ordenado(arr++);
is equivalent with
return ordenado(arr);
a++;
which leads to infinite number of function calls as #BLUEPIXY pointed out.
Corrected code
#include <stdio.h>
#include <stdlib.h>
int ordenado(int*);
int main() {
int i = 0, res = 0;
int* arr = NULL;
arr = (int*) malloc(sizeof (int));
scanf("%d", &arr[i]);
while (arr[i] != 0) {
i++;
arr = (int*) realloc(arr, (i + 1) * sizeof (int));
scanf("%d", &arr[i]);
}
res = ordenado(arr);
printf("\n%d ", res);
return 0;
}
int ordenado(int* arr) {
if (arr[0] == 0 || arr[1] == 0)
return 1;
if (arr[0] > arr[1])
return 0;
else
return ordenado(++arr);
}
Example inputs and outputs:
Input: 0
Output: 1
Input: 1 newline 0
Output: 1
Input: 1 newline 2 newline 3 newline 0
Output: 1
Input: 2 newline 1 newline 0
Output: 0
Input: 1 newline 2 newline 3 newline 2 newline 3 newline 0
Output: 0
In these lines:
arr = malloc(sizeof (int));
while (arr[i] != 0)
You cannot count on malloc'd memory having any particular value. It is uninitialized.
It looks like you are using an input zero as a sentinel. The proper way to do this is:
int i = 0;
int *arr = malloc(sizeof (int));
do {
i++;
arr = realloc (arr, (i + 1) * sizeof (int));
scanf ("%d", &arr[i-1]);
} while (arr[i-1] != 0);
I have also fixed element zero not having been assigned a value.
I suspect the error you experienced was caused by runaway recursion.
Your code has multiple problems:
you read the first element of the array before storing it: it is uninitialized, even just reading it invokes undefined behaviour.
you never store the first element in the array (at offset 0)
if the array has at least one non zero element, when you compare the last 2 elements, you will get an potential mismatch since the last element is 0;
when you recurse, you pass arr before incrementing it, hence causing an infinite recursion. The fact that you get an error proves that the compiler does not handle tail recursion, and your code eventually fails with a stack overflow.
If you can change the API for the ordenado function, you should pass it the number of actual elements in the array. This function is supposed to be recursive, choose an algorithm that will limit the recursion to avoid stack overflow if the compiler does not detect tail recursion.
Here is my suggestion:
#include <stdio.h>
#include <stdlib.h>
int ordenado(int *array, int count);
int main() {
int i = 0, n, res;
int *arr = NULL;
while (scanf("%d", &n) == 1 && n != 0) {
arr = realloc(arr, (i + 1) * sizeof(int));
if (!arr) {
printf("out of memory\n");
return 1;
}
arr[i++] = n;
}
res = ordenado(arr, i);
printf("%d\n", res);
return 0;
}
int ordenado(int *arr, int n) {
int m = n >> 1;
return (m == 0) ||
(ordenado(arr, m) && arr[m - 1] <= arr[m] && ordenado(arr + m, n - m));
}
NB: Reallocating the array one int at a time is painfully inefficient, but is not the topic of this discussion.