I'm fairly new to C and I'm working on a project. Given an integer array, I want to move all the zeros in it to the left of the array with the rest of the elements in any order to the right of all the zeros. The basic idea of my algorithm is to count the number of zeros in the array, create a new array with the number of zeros in it from the old array, and then "append" the rest of the non-zero integers onto this array. And then of course I print finished product.
int main(int argc, const char * argv[]) {
int a[10] = {3, 0, 1, 4, 0, 0, 7, 20, 1, 5};
int n = 10, count = 0;
// counts the number of 0's in the original array
for (int i = 0; i < n; ++i)
{
if (a[i] == 0)
{
++count;
}
}
// creates a new array and makes each element 0
int *array = NULL;
for (int j = 0; j < count; ++j)
{
array = realloc(array, (j + 1) * sizeof(int));
array[j] = 0;
}
// adds the nonzero elements of the array to the new array
for (int l = count; l < n; ++l)
{
array = realloc(array, l * sizeof(int)); // getting an error here
if (a[l] != 0)
{
array[l+count] = a[l];
}
}
// prints the array out in a nice format
printf("%s", "{");
for (int k = 0; k < n-1; ++k)
{
printf("%d%s", array[k], ",");
}
printf("%d", array[n-1]);
printf("%s", "}\n");
free(array);
return 0;
}
I'm getting a "Thread 1: EXC_BAD_ACCESS (code=1, address=0x40)" error when I run this code. I think it's got to do something with invalid pointers to the new array, but I'm not sure how to fix it.
array[l+count] = a[l];
This accesses the memory block that array points at beyond its allocated size. You have to do it differently, using a second index:
// adds the nonzero elements of the array to the new array
int l = count;
for (int j=0; j < n; ++j)
{
if (a[j] != 0)
{
array = realloc(array, (l+1) * sizeof(int));
array[l] = a[j];
++l;
}
}
About your algorithm:
I think u don't need to create a new array, just use a int tmp as swap area, and a int foundZeroCount as index, u swap 2 numbers at a time.
About memory allocation:
If u want to allocate memory for a fixed size array, just use malloc() to allocate array once, later when u need to extend the array, just call realloc() once.
About memory reset:
Just use memset(), and don't need a loop.
Suggestion - about c programming
Try improve your c basic, especially about array / pointer / memory, and try to know more functions from glibc.
Books like <The c programming language 2nd>, GNU c library document, and <The linux programming interface> would be useful, I guess.
The problem is with array[l+count] = a[l]; right when you are done allocating your 'zero-array' it's size is 3 and then you try to access (l + count)'th position which is 6.
And even if you have fixed those issues with memory it still wouldn't work because a[l] and further may still be zeros. (Your initial array is doesn't have zeroes in the beggining, remember?)
And there is a couple of suggestions:
use calloc() to build your initial array of zeros because as man states:
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory. The
memory is set to zero
First allocate then set because operations with memory are quite taxing for performance. It would be better for you to first allocate some memory and work with it instead of reallocating it each step. It would be much easier to keep track of as well.
Other answers address your immediate issue, that
array[l+count] = a[l];
attempts to access outside the bounds of the allocated space to which array points. I'll focus instead on your approach to the problem, which is flawed.
Dynamic memory allocation is comparatively expensive. You do not want to do any more than necessary, and it is particularly poor form to reallocate many times to increase by small increments each time, as you do.
Since you know at compile time how many elements you will need, dynamic allocation is altogether unnecessary here. You could instead do this:
int a[10] = {3, 0, 1, 4, 0, 0, 7, 20, 1, 5};
int array[10] = { 0 };
(Note also here that when an array initializer is provided, any array elements it does not explicitly initialize are initialized to 0.)
Even if you did not know at compile time how many elements you would need, it would be far better to perform the whole allocation in one chunk. Moreover, if you did that via calloc() then you would get automatic initialization of the allocated space to all-zeroes.
The count is known before defining the array. You can allocate memory using malloc as shown below.
array = malloc( count * sizeof(int)).
The error indicates you are trying to access address 0x40. This indicates one of the pointer has become NULL and you are trying to dereference ptr+0x40.
Before you start to hack away, take your time to consider the actual problem, which you have described as:
count the number of zeros in the array, create a new array with the number of zeros in it from the old array, and then "append" the rest of the non-zero integers onto this array.
Your comments say what the code should do, yet the code does something entirely different. Your algorithm to solve the problem is wrong - this, and nothing else, is the cause of the bugs.
To begin with, if the new array should contain all zeroes of the old array plus all non-zeroes, then common sense says that the new array will always have the same size as the old array. You don't even need to use dynamic memory allocation.
The code you have creates a new array and discards the old one, in the same memory location, over and over. This doesn't make any sense. On top of that, it is very ineffective to call realloc repeatedly in a loop.
You should do something like this instead:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, const char * argv[]) {
int a[10] = {3, 0, 1, 4, 0, 0, 7, 20, 1, 5};
const int n = 10;
// counts the number of 0's in the original array
int zeroes = 0;
for (int i = 0; i < n; ++i)
{
if (a[i] == 0)
{
++zeroes;
}
}
// creates a new array and makes each element 0
// there's actually no need to allocate this dynamically at all...
int *array = calloc(1, sizeof(int[n]) );
assert(array != NULL);
// skip zeroes, ie "move the zeroes from the original array"
int* not_zeroes = array + zeroes; // point at first item to contain "not zeroes"
// adds the non-zero elements of the original array to the new array
for (int i = 0; i < n; ++i)
{
if(a[i] != 0)
{
*not_zeroes = a[i];
not_zeroes++;
}
}
// prints the array out in a nice format
printf("%s", "{");
for (int i = 0; i < n; ++i)
{
printf("%d,", array[i]);
}
printf("}\n");
free(array);
return 0;
}
Related
I'm writing this code in C for some offline games but when I run this code, it says "runtime failure #2" and "stack around the variable has corrupted". I searched the internet and saw some answers but I think there's nothing wrong with this.
#include <stdio.h>
int main(void) {
int a[16];
int player = 32;
for (int i = 0; i < sizeof(a); i++) {
if (player+1 == i) {
a[i] = 254;
}
else {
a[i] = 32;
}
}
printf("%d", a[15]);
return 0;
}
Your loop runs from 0 to sizeof(a), and sizeof(a) is the size in bytes of your array.
Each int is (typically) 4-bytes, and the total size of the array is 64-bytes. So variable i goes from 0 to 63.
But the valid indices of the array are only 0-15, because the array was declared [16].
The standard way to iterate over an array like this is:
#define count_of_array(x) (sizeof(x) / sizeof(*x))
for (int i = 0; i < count_of_array(a); i++) { ... }
The count_of_array macro calculates the number of elements in the array by taking the total size of the array, and dividing by the size of one element.
In your example, it would be (64 / 4) == 16.
sizeof(a) is not the size of a, but rather how many bytes a consumes.
a has 16 ints. The size of int depends on the implementation. A lot of C implementations make int has 4 bytes, but some implementations make int has 2 bytes. So sizeof(a) == 64 or sizeof(a) == 32. Either way, that's not what you want.
You define int a[16];, so the size of a is 16.
So, change your for loop into:
for (int i = 0; i < 16; i++)
You're indexing too far off the size of the array, trying to touch parts of memory that doesn't belong to your program. sizeof(a) returns 64 (depending on C implementation, actually), which is the total amount of bytes your int array is taking up.
There are good reasons for trying not to statically declare the number of iterations in a loop when iterating over an array.
For example, you might realloc memory (if you've declared the array using malloc) in order to grow or shrink the array, thus making it harder to keep track of the size of the array at any given point. Or maybe the size of the array depends on user input. Or something else altogether.
There's no good reason to avoid saying for (int i = 0; i < 16; i++) in this particular case, though. What I would do is declare const int foo = 16; and then use foo instead of any number, both in the array declaration and the for loop, so that if you ever need to change it, you only need to change it in one place. Else, if you really want to use sizeof() (maybe because one of the reasons above) you should divide the return value of sizeof(array) by the return value of sizeof(type of array). For example:
#include <stdio.h>
const int ARRAY_SIZE = 30;
int main(void)
{
int a[ARRAY_SIZE];
for(int i = 0; i < sizeof(a) / sizeof(int); i++)
a[i] = 100;
// I'd use for(int i = 0; i < ARRAY_SIZE; i++) though
}
int squaring_function (int *array, int i);
int main()
{
int array[5];
int i;
for(i=0; (i <= 5) ; i++)
{
array[i] = i;
printf("\nArray value %d is %d",i,array[i]);
}
for(i=0; (i <= 5) ; i++)
{
array[i] = (squaring_function(array, i));
printf("\nSquared array value %d is %d",i,array[i]);
}
return 0;
}
int squaring_function (int *array, int i)
{
return pow((array[i]),2);
}
I'm trying to use this squaring_function to square each value in turn in my array (containing integers 0 to 5). It seems to work however the last value (which should be 5)^2 is not coming up as 25. cmd window
I have tried reducing the array size to 5 (so the last value is 4) however this prints an incorrect number also.
I'm quite new to C and don't understand why this last value is failing.
I'm aware I could do this without a separate function however I'd quite like to learn why this isn't working.
Any help would be much appreciated.
Thanks,
Dan.
There are 2 bugs in your code. First is that you're accessing array out of bounds. The memory rule is that with n elements the indices must be smaller than n, hence < 5, not <= 5. And if you want to count up to 5, then you must declare
int array[6];
The other problem is that your code calculates pow(5, 2) as 24.99999999 which gets truncated to 24. The number 24 went to the memory location immediately after array overwriting i; which then lead to array[i] evaluating to array[24] which happened to be all zeroes.
Use array[i] * array[i] instead of pow to ensure that the calculation is done with integers.
The code
int array[5];
for(int i=0; (i <= 5) ; i++)
exceeds array bounds and introduces undefined behaviour. Note that 0..5 are actually 6 values, not 5. If you though see some "meaningful" output, well - good or bad luck - it's just the result of undefined behaviour, which can be everything (including sometimes meaningful values).
Your array isn't big enough to hold all the values.
An array of size 5 has indexes from 0 - 4. So array[5] is off the end of the array. Reading or writing past the end of an array invokes undefined behavior.
Increase the size of the array to 6 to fit the values you want.
int array[6];
The other answers show the flaws in the posted code.
If your goal is to square each element of an array, you can either write a function which square a value
void square(int *x)
{
*x *= *x;
}
and apply it to every element of an array or write a function which takes an entire array as an input and perform that transformation:
void square_array(int size, int arr[size])
{
for (int i = 0; i < size; ++i)
{
arr[i] *= arr[i];
}
}
// ... where given an array like
int nums[5] = {1, 2, 3, 4, 5};
// you can call it like this
square_array(5, nums); // -> {1, 4, 9, 16, 25}
I am trying to understand how malloc works. I did a program searches for the largest element in a one dimensional array int.
This is the code.
#include <stdlib.h>
#include <stdio.h>
void largest_element(int *nbr)
{
int i;
int n;
int m;
i = 1;
nbr = (int*)malloc(sizeof(nbr) + 8);
while (i < 8)
{
if (*nbr < *(nbr + i))
*nbr = *(nbr + i);
i++;
}
printf("%d ", *nbr);
}
int main(void)
{
int i;
int tab[8] = {11, 2, 4, 5, 9, 7, 8, 1};
int n = sizeof(tab)/sizeof(int);
i = 0;
largest_element(&tab[8]);
return(0);
}
The program works without malloc but how can I make it work with malloc? What did I do wrong and why does my code only give me garbage numbers?
I think you are lost with pointers and arrays so you can not understand malloc properly (no offense, everyone who is learning C do the same mistake).
Let's take your main function. When you run:
int tab[8] = {11, 2, 4, 5, 9, 7, 8, 1};
You staticly allocate an array of 8 integers and you fill it with your numbers.
The dynamic equivalent would be:
int* tab = malloc(sizeof(int) * 8);
tab[0] = 11;
tab[1] = 2;
/// Etc...
tab[7] = 1;
First thing: the first element of an array has the index 0. So in your largest_element function, i should be initialized at 0 instead of 1.
The reason is, when you deal with array, you deal with pointers. In your case, tab is a pointer to the first element of the array. So, when you do tab[3], you get the forth element of your array.
Second thing: when you do:
largest_element(&tab[8]);
You send to your function the eighth element after the begining of your array. The problem is: you do not own this memory area! You own the memory only until tab[7].
If you want to send the complete array to your function, just use:
largest_element(tab);
Now, let's talk about your largest_element function.
You do not need to call malloc here since the memory is already allocated
When you do *nbr = *(nbr + i); you change the value of the first element of your array. I think you wanted to do m = *(nbr + i); isn't it.
Why do you not use the nbr[i] instead of *(nbr + i)?
A correct implementation of this function would be something like (not tested):
void largest_element(int *nbr)
{
int i = 0;
int max = 0;
while (i < 8)
{
if (max < nbr[i])
max = nbr[i];
i++;
}
printf("%d ", m);
}
A last thing, using malloc involve using the function free to release the memory when you do not need it anymore.
What did I do wrong and why does my code only give me garbage numbers??
In largest_element(int *nbr) nbr points to the array tab in main (at least if you call it like this: largest_element(tab); instead of like this largest_element(&tab[8]);
Then you call nbr = (int*)malloc(sizeof(nbr) + 8); now nbr points to some allocated memory which has not been initialized and which contains garbage values. Now if you read from that memory it's normal that you get garbage values.
You simply don't need malloc for this problem, just as you don't need floating point math or file system related functions for this problem.
I have observed that memory allocated for array seems to be dynamic.
Here is the sample code I found in this tutorial:
#include <stdio.h>
main() {
int LA[] = {1,3,5,7,8};
int item = 10, k = 3, n = 5;
int i = 0, j = n;
printf("The original array elements are :\n");
for(i = 0; i<n; i++) {
printf("LA[%d] = %d \n", i, LA[i]);
}
n = n + 1;
while( j >= k){
LA[j+1] = LA[j];
j = j - 1;
}
LA[k] = item;
printf("The array elements after insertion :\n");
for(i = 0; i<n; i++) {
printf("LA[%d] = %d \n", i, LA[i]);
}
}
and sample output:
The original array elements are :
LA[0]=1
LA[1]=3
LA[2]=5
LA[3]=7
LA[4]=8
The array elements after insertion :
LA[0]=1
LA[1]=3
LA[2]=5
LA[3]=10
LA[4]=7
LA[5]=8
How its working I did not get.
First, a general statement, for an array defined without explicit size and initialized using brace-enclosed initializer, the size will depend o the elements in the initializer list. So, for your array
int LA[] = {1,3,5,7,8};
size will be 5, as you have 5 elements.
C uses 0-based array indexing, so the valid access will be 0 to 4.
In your code
LA[j+1] = LA[j];
trying to access index 6, (5+1) which is out of bound access. This invokes undefined behavior.
Output of a code having UB cannot be justified in any way.
That said, main() is technically an invalid signature as per latest C standards. You need to use at least int main(void) to make the code conforming for a hosted environment.
The code has a buffer overflow bug! Arrays in C cannot be extended! You need to allocate enough space when you declare/define it.
You can declare additional space by supplying a size in the declaration:
int LA[10] = {1,3,5,7,8};
LA will now have room for 10 elements with index 0 through 9.
If you want more flexibility you should use a pointer and malloc/calloc/realloc to allocate memory.
Note:
There is a second bug in the copying. The loop starts one step too far out.
With j starting at 5 and assigning index j+1 the code assigns LA[6], which is the 7th element. After the insertion there are only 6 elements.
My conclusion from these 2 bugs is that the tutorial was neither written nor reviewed by an experienced C programmer.
To add on to the other answers, C/C++ do not do any bounds checking for arrays.
In this case you have a stack allocated array, so as long as your index does not leave stack space, there will be no "errors" during runtime. However, since you are leaving the bounds of your array, it is possible that you may end up changing the values of other variables that are also allocated in the stack if it's memory location happens to be immediately after the allocated array. This is one of the dangers of buffer overflows and can cause very bad things to happen in more complex programs.
running int a strange scenario where malloc is allocating more memory than I ask for:
void function (int array [], int numberOfElements) {
int *secondArray = malloc(sizeof(int) * numberOfElements/2);
for (int i = 0; i < numberOfElements / 2; i++) {
secondArray[i] = array[i];
}
}
Let's say array is a some 10 numbers. When I print out secondArray after the above code, I get:
so first of all, the array should be 5 elements. But second, why the 0's in the end? I'm mallocing only space for 10/2 = 5 ints.
EDIT:
printing code:
for (int d = 0; d < numberOfElements; d++) {
printf("%i ", secondArray[d]);
}
hmm I might have just answered my own question here, I'm guessing it's the printing beyond secondArray that shows 0, not the array itself.
-
Actually, the problem is that I was also not doing this:
secondArray[numberOfElements] = '\0';
That is why it was printing beyond.
malloc is actually allocating exactly the right amount.
However, you're accessing memory beyond the allocation.
What exists there is completely undefined and could really be anything.
In your case, it was one "junk" number and four zeroes.
You are just lucky. Malloc can and sometimes does ask from more memory off the OS - Taking into account paging. Sometimes it does not even need to ask the OS for memory as it has asked for extra earlier. Therefore the malloc could ask for a page of memory - more that enough to satisfy your request and the extra memory happens to be filled with zeros.
You are in the land of undefined behaviour. So all bets are off.
/** its print 0 0 0 0 because in C no array bound if you define your array
* size is 4 but
* you want to store data more than array size you can store so you print your
* array.
* for(i = 0; i < numberOfElements; i++) its give data and 0 also because you
* store the data
* only 5 position but you print it max size so it give you 0 0 0
*/
int *secondArray = malloc(sizeof(int) * numberOfElements/2); // no matter either use it or
int *secondArray = malloc(sizeof(int));
// ^^^ this will take same memory