Related
I am trying to make a pointer P return to me the index of the first occurrence of given number in an array using count function that i wrote (J's job is to return the number of occurrences), the idea here is that im trying to write a function that returns 2 values instead of 1 (P returns index of first occurrence and J returns its number) in such way:
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
}
I am fully aware aware that instead of using int *p, i can simply use P and pass its address in such way:
void printarray(int h[],int size){
for(int i=0;i < size ;i++)
{
printf(" %d ",h[i]);
}
printf("\n");
}
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int p;
int h[] = {1,2,3,4,5,1,1,3,4};
printarray(h,sizeof(h)/sizeof(int));
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", p,j);
}
What Really intrigues me is that why does it show a segmentation fault when using the pointer ? or am i just wrong about using a pointer in the first place and i should pass the address of an int in case i want my function to return 2 values for me ?
That which is a pointer has to point to something. So when you wrote int *p = NULL; you didn't give it somewhere to point. You could have done int n; int *p = &n; and proceed to pass p.
But it gets bumpy from here. You tried to write p = &i; inside the function. While that's completely valid code, from that point, assigning to *p will mess up your loop control function. This is not what you want. In the "I know I can" section you have the more reasonable *p = i;.
I'm guessing you want to know how to pass something allocated in the function to its caller. You can in fact do this; there's standard library functions designed for this task. You can in fact write
int count(int h[],int **p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = malloc(sizeof(int));
**p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
if (p) {
printf("%d %d", *p,j);
free(p);
} else {
printf("(no index) %d", j);
}
}
So what happened here is we have a pointer in main() that is initialized to point nowhere, may or may not be set in count to point to the index. If nothing is found, p will still point to NULL (nowhere). The function malloc() returns the newly allocated memory so that p has somewhere to point; and the function free returns it.
** is a simple idea that gives people headaches. Since a pointer is * we add another * when we want a pointer to a pointer, so we can change that pointer. Just don't ask how deep you can go. The answer is don't try. Two happens a lot; three requires a good justification, and more than three is almost never done. More than two really is a headache and nobody wants headaches on their headaches. The limit is way higher. Nobody goes there.
It probably seems rather pointless, and it is. malloc() is used to allocate entire arrays in the function (whose size isn't known until runtime) and return them to the caller. A single int just isn't worth managing like this (the pointer is bigger than it is), but for an array it makes sense. So much that in big programs, almost everything is on the heap; unlike the small programs everybody starts with where almost everything is on the stack (local variables are on the stack).
You thinking about what you want to do correctly, but you are over complicating how to do it a bit. Instead of all the if ... else ... statements, what if you just used a flag like what you call bool (but let's rename it to something that won't conflict with the type from stdbool.h), call it first_set instead. Initialize it with a value of 0 (false) to begin with, and then when you find the first occurrence, update first_set = 1;
If you step back and thing of what your primary check needs to be, all you are really worried about locating in your array is the first, and all remaining indexes where the given value (let's call val instead of d) is equal to the array element. (and since a count, a length and an array index cannot be negative, let's choose size_t as the type for the positive counting values). To track the number of occurrences, let's use occurs as the variable (helps keep things readable in long programs)
So all you really want to do is loop over each element in your array and check if the current element is equal to the value you are searching for. That is the primary concern from which all other actions can be taken. You can keep your parameters in the order you like, but I find it easier to think about the function (1) taking an array, (2) of a given number of elements, where I will find (3) the first occurrence or (4) a given value. (whatever makes sense to you, but is also readable to whoever works on your code later) So with a slight tweak of the ordering (at least for my old eyes), you could set up your function to loop over each element and locate all of the occurrences of a given value as:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
...
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
The only thing left to add is how to set the first occurrence. While you talk in terms of locating the "address" of the first occurrences in the function, what I think you really mean is locating the "index" of the first occurrence within the array. You can convert the index back to an address in the calling function and not have to worry about passing something that can hold the address (which would require passing a pointer-to-pointer rather than a pointer-to int)
So the first time the test of a[i] == val tests true, you want to capture the index and save it, ensuring you don't change it for any of the other times a[i] == val tests true during your loop. You have your first_set flag that is currently set to 0 (false), so all you really need to capture your first index in the array where val occurs is:
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
If you put that in place of the ... placeholder in the function above, you would have:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
Short and sweet, no else needed, just a check of your flag first_set and if it isn't set, capture the index and set first_set true so you don't change in during the remainder of your loop. Your function makes the index of the first occurrence of val available back in the calling function by updating the value at the address held by the pointer first. The function returns the total number of occurrences for val in your array so it too is available to the caller. (with a slight change of type to size_t)
(another benefit of using size_t on platforms where size_t is larger than int is your array (or allocated block) can hold more than INT_MAX values and your code will still work without risk of integer overflow if a count exceeds what can be represented by an int)
Putting it altogether in a short example that creates an array of 100 elements holding random values from -10 to 10 and then chooses the value to find by choosing a random value in that range, you could check that all works as expected as follows:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NELEM 100 /* if you need a constant, #define one (or more) */
#define PERROW 10
#define LO_LIM -10
#define HI_LIM 10
int rand_in_range (int lowlim, int highlim)
{
return rand() % (highlim - lowlim + 1) + lowlim;
}
void arr_fill_rand (int *a, size_t nelem, int lowlim, int highlim)
{
for (size_t i = 0; i < nelem; i++)
a[i] = rand_in_range (lowlim, highlim);
}
void arr_prn (int *a, size_t nelem, const char* fmt)
{
const char *format = fmt != NULL ? fmt : " %d";
for (size_t i = 0; i < nelem; i++) {
if (i && i % PERROW == 0)
putchar ('\n');
printf (format, a[i]);
}
putchar ('\n');
}
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
int main (void) {
int arr[NELEM] = {0}, /* array of NELEM set all zero */
val = 0; /* value to find */
size_t first = 0, /* index of first occurrence */
occurs = 0; /* total no. of occurrences */
srand (time(NULL)); /* seed random number generator */
val = rand_in_range (LO_LIM, HI_LIM); /* random in LO to HI (inclusive) */
arr_fill_rand (arr, NELEM, LO_LIM, HI_LIM); /* fill with random values in range */
arr_prn (arr, NELEM, " % 3d");
occurs = arr_occurrences (arr, NELEM, &first, val); /* get occurrences of val */
printf ("\n%d occurs first in array of %d " /* output results */
"elements ranging from %d to %d at:\n"
" index : %zu\n"
" address : %p\n"
"and occurs a total of %zu times.\n",
val, NELEM, LO_LIM, HI_LIM,
first, (void*)&arr[first], occurs);
}
(note: you never need more than one call to printf() (or fputs() or puts()) to provide on block of output, regardless of the number of lines it contains. You can keep things readable in longer output by breaking the string up into adjacent strings (newlines and other whitespace between them is ignored) and the compiler with create a single string to output from all adjacent string literals)
Example Use/Output
The program outputs the array and then outputs the results with the index of the first occurrence (and it's actual address if that is what you wanted) along with the total number of times the value of interest was found:
$ ./bin/arr_rand_1st_occ+count
3 -10 2 10 2 -9 4 5 -3 7
-4 -6 10 -4 8 -5 8 5 -10 10
10 6 -3 2 -5 1 1 8 10 -1
6 0 -1 -5 -1 10 -6 -10 4 1
5 -10 6 5 -4 1 8 -8 -4 8
-9 -7 2 -4 5 7 5 -7 3 4
2 -4 -6 10 1 1 9 5 0 0
-7 -6 -2 9 7 3 -2 4 3 4
2 4 5 -9 8 -3 6 2 0 -2
-6 -10 4 -2 8 -8 7 6 5 -4
8 occurs first in array of 100 elements ranging from -10 to 10 at:
index : 14
address : 0x7ffea2fb5938
and occurs a total of 7 times.
The array is output with 10 values PERROW to make things easier to read. Remember when confirming the results, arrays are zero-indexed in C.
Last note is unless you are programming in a freestanding environment (without the benefit of any OS), the allowable declarations for main for are int main (void) and int main (int argc, char *argv[]) (which you will see written with the equivalent char **argv). See: C11 Standard - §5.1.2.2.1 Program startup(p1). See also: What should main() return in C and C++?
In a freestanding environment (such as programming on a microcontroller) without the benefit of an operating-system, the name and type of the function called at program startup are implementation-defined. See: C11 Standard - 5.1.2.1 Freestanding environment
Look things over and let me know if you have further questions.
Your program behaviour is undefined because it end up dereferencing a NULL pointer here:
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
^^
|
Dereferencing p which is a NULL pointer
The way you are passing the p pointer from main() function to count() function, you are passing NULL. That means, in context of your program, this
j = count(h, p , sizeof(h)/sizeof(int) , 1);
is equivalent to this
j = count(h, NULL , sizeof(h)/sizeof(int) , 1);
The count() function parameter p will receive NULL as argument i.e. it's equivalent to p = NULL (where p is count() function parameter).
Whatever you assign to p in count() function, you are actually modifying a local variable of count() function. No changes are going to reflect in pointer variable p of main() function and it will remain a NULL pointer.
Now, lets come to the count() function.
In this snip of code of count() function:
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
the scope and life of loop variable i is within the for loop block. Once, the loop exit the lifetime of i is ended. JFYI - accessing an object outside of its lifetime is undefined behaviour. So, if p hold &i and out of loop body if your program access p then it will lead to undefined behaviour. Also, *p=-1; statement in count() will also lead to undefined behaviour because, in count() function p will be a NULL pointer if bool==0.
Remember, if a function is passing a pointer to another function as a argument and expecting that function to modify the value of pointer, which it receive as parameter, then the pointer should be pointing to a valid memory location before the calling function access and modify it's memory contents or the caller function should pass address of pointer as argument and let the calling function allocate memory dynamically to it so that it should be accessible from the caller function as well (which is main() function, in your case).
There are couple ways to achieve this.
Method I:
Pass a valid memory location to calling function.
Either pass address of a local variable of caller function as argument (this is same as your second code snippet)
int main (void) {
int j;
size_t res = 0;
size_t *p = &res; // p is pointing to res variable
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
return 0;
}
Or allocate memory to pointer in caller function and pass it
int main (void)
{
int j;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE); // or whatever you want to do in case of allocation failure
}
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
free(p);
return 0;
}
and the count() function implementation for both the above cases:
int count (int h[], size_t *p, size_t size, int d) {
int j = 0;
for (size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if (j == 0) {
*p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
Method II:
Pass the address of p and dynamically allocate memory to p in count() function before accessing it. Note that, objects with allocated storage duration live until they are destroyed by a call to free(). So, if count() function allocates memory to a pointer, whose address passed as argument to count() function from main() function, then that memory will be accessible in main() function as well via pointer variable p.
#include <stdio.h>
#include <stdlib.h>
int count (int h[], size_t **p, size_t size, int d) {
int j = 0;
for(size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if ((j == 0) && (p != NULL)) {
*p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE);
}
**p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
int main (void) {
int retval;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 3;
retval = count (h, &p, sizeof (h) / sizeof (int), num);
if (retval != -1) {
printf ("%zu %d\n", *p, retval);
} else {
printf ("%d not found\n", num);
}
// free memory once you are done with it
if (p != NULL) {
free (p);
}
return 0;
}
Additional:
Using void as return type of main function is not as per standards. The return type of main function should be int.
You are trying to return pointer pointing to a place which will be no longer valid once the loop completed it's execution, either declare i outside for or don't use the pointer part, as dereferencing a null pointer is illegal, also, you get segmentation fault when you try to access memory you have no business with and no permission to read or write, in this case, pointing to a memory location which is out of scope.
Instead of returning a pointer,simply create a local array of same type in the function, first index for first occurence of the given number, and second index for the total occurence, and return the array but make sure the return type should be pointer of same type.
edit: thanks Mr. Joshua, for pointing out the mistake.
I have two functions in my main function.
I've tried to accomplish this problem with pointers, but as a beginner, it is very complicated to work with this.
int main(){
int *p;
p = function_A();
function_B(p);
return 0;
}
int function_A(){
static int myArray[3];
myArray[0] = 11;
myArray[1] = 22;
myArray[2] = 33;
return myArray;
}
int function_B(int *myPointer){
// Here I just want to print my array I've got from function_A() to the
// console
printf("%d", *myPointer)
return 0;
}
function_A should return a array and function_B should take this array.
Thanks!
There are some issues your compiler will already have told you.
First, you should define the functions before calling them, or at least forward declare them.
Second, to return an array, you need to return a pointer to the first element of this array, i.e. return type is int * and not int.
Third, as FredK pointed out, when you receive just a pointer, you have no chance to determine how many elements are in the array it points to. You can either terminate the array with a specific value, e.g. 0, or you need to return the size of the array, too.
See the following adaptions made to your program:
int* function_A(int *size){
static int myArray[3];
myArray[0] = 11;
myArray[1] = 22;
myArray[2] = 33;
if (size) {
*size = 3;
}
return myArray;
}
void function_B(int *myPointer, int size){
for (int i=0; i<size; i++) {
printf("%d\n", myPointer[i]);
}
}
int main(){
int *p;
int size=0;
p = function_A(&size);
function_B(p,size);
return 0;
}
Note: a reference to an array degrades to the address of the first byte of the array.
the following proposed code:
cleanly compiles
incorporates the comments to the question
assumes the programmer already knows the size of the array
performs the desired functionality
appended '\n' to format string of calls to printf() so output on separate lines
and now, the proposed code:
#include <stdio.h>
int * function_A( void );
void function_B(int *myPointer);
int main( void )
{
int *p;
p = function_A();
function_B(p);
return 0;
}
int * function_A()
{
static int myArray[3];
myArray[0] = 11;
myArray[1] = 22;
myArray[2] = 33;
return myArray;
}
void function_B(int *myPointer)
{
printf("%d\n", myPointer[0]);
printf("%d\n", myPointer[1]);
printf("%d\n", myPointer[2]);
}
a run of the program produces the following output:
11
22
33
Let's say you have a function that creates an array of ints:
int *create_int_array(const size_t num)
{
int *iarray;
size_t i;
if (num < 1)
return NULL; /* Let's not return an empty array. */
iarray = malloc(num * sizeof iarray[0]);
if (!iarray)
return NULL; /* Out of memory! */
/* Fill in the array with increasing integers. */
for (i = 0; i < num; i++)
iarray[i] = i + 1;
return iarray;
}
Let's say tou have a function that calculates the sum of the integers in the array. If we ignore any overflow issues, it could look like this:
int sum_int_array(const int *iarray, const size_t num)
{
int sum = 0;
size_t i;
/* Sum of an empty array is 0. */
if (num < 1)
return 0;
for (i = 0; i < num; i++)
sum += iarray[i];
return sum;
}
Note that sizeof is not a function, but a C language keyword. Its argument is only examined for its size. Thus, sizeof iarray[0] yields the size of each element in iarray, and is completely safe and valid even if iarray is undefined or NULL at that point. You see that idiom a lot in C programs; learn to read it as "size of first element of iarray", which is the same as "size of each element in iarray", because all C array elements have the exact same size.
In your main(), you could call them thus:
#ifndef NUM
#define NUM 5
#endif
int main(void)
{
int *array, result;
array = create_int_array(NUM);
if (!array) {
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
}
result = sum_int_array(array, NUM);
printf("Sum is %d.\n", result);
free(array);
return EXIT_SUCCESS;
}
As you can see, there is really not much to it. Well, you do need to get familiar with the pointer syntax.
(The rule I like to point out is that when reading pointer types, read the specifiers from right to left, delimited by * read as a pointer to. Thus, int *const a reads as "a is a const, a pointer to int", and const char **b reads as "b is a pointer to a pointer to const char".)
In this kind of situations, a structure describing an array makes much more sense. For example:
typedef struct {
size_t max; /* Maximum number of elements val[] can hold */
size_t num; /* Number of elements in val[] */
int *val;
} iarray;
#define IARRAY_INIT { 0, 0, NULL }
The idea is that you can declare a variable of iarray type just as you would any other variable; but you also initialize those to an empty array using the IARRAY_INIT macro. In other words, thus:
iarray my_array = IARRAY_INIT;
With that initialization, the structure is always initialized to a known state, and we don't need a separate initialization function. We really only need a couple of helper functions:
static inline void iarray_free(iarray *array)
{
if (array) {
free(array->val);
array->max = 0;
array->num = 0;
array->val = NULL;
}
}
/* Try to grow the array dynamically.
Returns the number of elements that can be added right now. */
static inline size_t iarray_need(iarray *array, const size_t more)
{
if (!array)
return 0;
if (array->num + more > array->max) {
size_t max = array->num + more;
void *val;
/* Optional: Growth policy. Instead of allocating exactly
as much memory as needed, we allocate more,
in the hopes that this reduces the number of
realloc() calls, which tend to be a bit slow.
However, we don't want to waste too much
memory by allocating and then not using it. */
if (max < 16) {
/* Always allocate at least 16 elements, */
max = 16;
} else
if (max < 65536) {
/* up to 65535 elements add 50% extra, */
max = (3*max) / 2;
} else {
/* then round up to next multiple of 65536, less 16. */
max = (max | 65535) + 65521;
}
val = realloc(array->val, max * sizeof array->val[0]);
if (!val) {
/* We cannot grow the array. However, the old
array is still intact; realloc() does not
free it if it fails. */
return array->max - array->num;
}
/* Note: the new elements in array->val,
array->val[array->max] to
array->val[max-1], inclusive,
are undefined. That is fine, usually,
but might be important in some special
cases like resizing hash tables or such. */
array->max = max;
array->val = val;
}
return array->max - array->num;
}
/* Optional; same as initializing the variable to IARRAY_INIT. */
static inline void iarray_init(iarray *array)
{
array->max = 0;
array->num = 0;
array->val = NULL;
}
The static inline bit means that the functions are only visible in this compilation unit, and the compiler is free to implement the function directly at the call site. Basically, static inline is used for macro-like functions and accessor functions. If you put the structure in a header file (.h), you'd put the related static inline helper functions in it as well.
The growth policy part is only an example. If you omit the growth policy, and always reallocate to array->num + more elements, your code will call realloc() very often, potentially for every int appended. In most cases, doing it that often will slow down your program, because realloc() (as well as malloc(), calloc()) is kind-of slow. To avoid that, we prefer to pad or round up the allocation a bit: not too much to waste allocated but unused memory, but enough to keep the overall program fast, and not bottlenecked on too many realloc() calls.
A "good growth policy" is very much up to debate, and really depends on the task at hand. The above one should work really well on all current operating systems on desktop machines, laptops, and tablets, when the program needs only one or only a handful of such arrays.
(If a program uses many such arrays, it might implement an iarray_optimize() function, that reallocates the array to exactly the number of elements it has. Whenever an array is unlikely to change size soon, calling that function will ensure not too much memory is sitting unused but allocated in the arrays.)
Let's look at an example function that uses the above. Say, the obvious one: appending an integer to the array:
/* Append an int to the array.
Returns 0 if success, nonzero if an error occurs.
*/
int iarray_append(iarray *array, int value)
{
if (!array)
return -1; /* NULL array specified! */
if (iarray_need(array, 1) < 1)
return -2; /* Not enough memory to grow the array. */
array->val[array->num++] = value;
return 0;
}
Another example function would be one that sorts the ints in an array by ascending or descending value:
static int cmp_int_ascending(const void *ptr1, const void *ptr2)
{
const int val1 = *(const int *)ptr1;
const int val2 = *(const int *)ptr2;
return (val1 < val2) ? -1 :
(val1 > val2) ? +1 : 0;
}
static int cmp_int_descending(const void *ptr1, const void *ptr2)
{
const int val1 = *(const int *)ptr1;
const int val2 = *(const int *)ptr2;
return (val1 < val2) ? +1 :
(val1 > val2) ? -1 : 0;
}
static void iarray_sort(iarray *array, int direction)
{
if (array && array->num > 1) {
if (direction > 0)
qsort(array->val, array->num, sizeof array->val[0],
cmp_int_ascending);
else
if (direction < 0)
qsort(array->val, array->num, sizeof array->val[0],
cmp_int_descending);
}
}
Many new programmers do not realize that the standard C library has that nifty and quite efficient qsort() function for sorting arrays; all it needs is a comparison function. If the direction is positive for iarray_sort(), the array is sorted in ascending order, smallest int first; if direction is negative, then in descending order, largest int first.
A simple example main() that reads in all valid ints from standard input, sorts them, and prints them in ascending order (increasing value):
int main(void)
{
iarray array = IARRAY_INIT;
int value;
size_t i;
while (scanf(" %d", &value) == 1)
if (iarray_append(&array, value)) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
iarray_sort(&array, +1); /* sort by increasing value */
for (i = 0; i < array.num; i++)
printf("%d\n", array.val[i]);
iarray_free(&array);
return EXIT_SUCCESS;
}
If size of array is indeed 3 (or other small fixed value), then you can simply use structs as values, something like:
struct ints3 {
int values[3];
// if needed, can add other fields
}
int main(){
struct ints3 ints;
ints = function_A();
function_B(&ints);
return 0;
}
// note about function_A signature: void is important,
// because in C empty () means function can take any arguments...
struct ints3 function_A(void) {
// use C designated initialiser syntax to create struct value,
// and return it directly
return (struct ints3){ .values = { 11, 22, 33 } };
}
int function_B(const struct ints3 *ints) {
// pass struct as const pointer to avoid copy,
// though difference to just passing a value in this case is insignificant
// could use for loop, see other answers, but it's just 3 values, so:
printf("%d %d %d\n", ints->values[0], ints->values[1], ints->values[2]);
return 0; // does this function really need return value?
}
I am getting a segmentation fault from the below program.
#include <stdio.h>
#include <string.h>
void removeProcess(int*, int);
void removeProcessN(char**, int, int);
void main() {
int numPro = 0, quanTime = 0, contTime = 0, i, elemNum, time = 0;
//Supply variables with user input
printf("Enter number of processes: ");
scanf("%d", &numPro);
printf("Enter context switch time: ");
scanf("%d", &contTime);
printf("Enter quantum of time: ");
scanf("%d", &quanTime);
//Create array of number of process time
int proTime[numPro];
//Create string array for better output
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
elemNum = 0;
//While a process remains active
while (numPro != 0) {
//Retrieves the element being worked with
elemNum = elemNum % numPro;
//Describe process working with
printf("Executing process %s\nStart time = %d\n", proNames[elemNum], time);
proTime[elemNum] -= quanTime;
//If process time complete, remove process
if (proTime[elemNum] <= 0){
removeProcess(proTime, elemNum);
removeProcessN(proNames, elemNum, numPro);
--numPro;
}
//Add amount of time with context time
time = time + quanTime + contTime;
elemNum++;
}
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcessN(char **array, int numElem, int elem) {
char *temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < elem; i++) {
if (i == numElem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
/**
*#param *array pointer to an array of integers
*#param elem int of the element to remove
* Removes an element 'elem' from the supplied integer array.
*/
void removeProcess(int *array, int elem) {
//Number of elements in the array
int numElem = sizeof(array) / sizeof(int);
int temparray[numElem - 1];
//Copy array to temparray except for elem to remove
int i;
for (i = 0; i < numElem; i++) {
if (i == elem) {
continue;
} else {
temparray[i] = array[i];
}
}
//End by setting the pointer of array to the temparray
array = temparray;
}
I know the segmentation fault is coming from sprintf. I am trying to simulate how an operating system would complete a process using round robin. I have tried using sprintf because that's what tutorials were saying online to use when trying to manipulate strings. The removeProcessN is just removing an index from the array proNames. I am mostly just concerned with the sprintf.
I have tried malloc when I do the sprintf but it would not even compile at that point. If someone could offer an explanation I'd be appreciative.
The problem here is that proNames is an array of pointers, but they are
uninitialized, so passing it to sprintf to write something, will crash. You
would have either use a double array or allocate memory with malloc. But as
you are only printing integers and the string representatuion of integers has a
maximal length, allocating memory with malloc will be more harder, because you
have to check that malloc doesn't return NULL, you have to free the memory
later, etc.
So I'd do:
char proNames[numPro][30]; // 28 characters for an int (usually 4 bytes long)
// should be more than enough
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
sprintf(proNames[i], "p%d", i);
}
Your removeProcessN would need to change as well:
void removeProcessN(int numElem, int elem, int dim, char (*array)[dim]) {
for(int i = elem; i < numElem - 1; ++i)
strcpy(array[i], array[i+1]);
array[numElem - 1][0] = 0; // setting last element to empty string
}
Note that I moved the array argument at the last position, otherwise numElem
is not known and the compiler would return an error.
And now you can call it like this:
removeProcessN(elemNum, numPro, 30, proNames);
The 30 comes from the char proNames[numProp][30]; declaration.
I'd like to comment on the last line of your function removeProcessN:
//End by setting the pointer of array to the temparray
array = temparray;
That is not correct, first because temparray is local variable and ceases to
exist when the function returns. And array is local variable in the function,
so changing it doesn't affect anybody.
The alternative with memory allocation would look like this:
char *proNames[numPro];
//Retrieves process time from user
for (i = 0; i < numPro; i++){
printf("Enter execution time for process %d: ", i);
scanf("%d", proTime + i);
int len = snprintf(NULL, 0, "p%d", i);
proNames[i] = malloc(len + 1);
if(proNames[i] == NULL)
{
// error handling, free the previously allocated
// memory, and return/exit
}
sprintf(proNames[i], "p%d", i);
}
and removeProcessN:
void removeProcessN(char **array, int numElem, int elem) {
char *to_remove = array[elem];
for(int i = elem; i < numElem - 1; ++i)
array[i] = array[i+1];
free(to_remove);
array[numElem - 1] = NULL; // setting last element to NULL
// makes freeing easier as
// free(NULL) is allowed
}
And the way you originally called the removeProcessN would be OK.
If you eventually call removeProcessN for all processes, then all the memory
should be freed because removeProcessN frees it. If there are some elements
that remain in the array, then you have to free them later.
OP posted in the comments
My theory was that temparray would be a pointer to an array so I could just remove an index from the main array.
So when I say array = temparray, the pointer for array points to temparray. I know it worked for removeProcess. Is it different for strings?
The array = temparray also has no effect in removeProcess, array is still
a local variable and changing where it points to has no effect at all, because
you are changing a local variable only.
Besides the code is wrong:
int numElem = sizeof(array) / sizeof(int);
this only works for pure arrays, it does not work for pointers because
sizeof(array) returns you the size that a pointer of int needs to be stored.
Like the other function, you need to pass the site the array to the function.
If you say that this function worked, then just only by accident, because it
yields undefined behavior. By incorrectly calculating the number of elements,
temparray will have the wrong size, so here temparray[i] = array[i]; you may
access beyond the bounds which leads to undefined behaviour. Undefined behaviour
means that you cannot predict what is going to happen, it could be anything from
crashing to formatting your hard drive. Results that result from undefined
behaviour are useless.
And again array = temparray; just changes where the local variable array is
pointing, the caller of removeProcess doesn't see that.
The correct version would be:
int removeProcess(int *array, int elem, int numElem) {
if(array == NULL)
return 0;
// nothing to do if the elemnt to be removed is
// the last one
if(elem == numElem - 1)
return 1;
// overwriting the memory, because memory
// regions overlap, we use memmove
memmove(array + elem, array + elem + 1, numElem - elem - 1);
return 0;
}
So, to make it clear:
Let's look at this code:
void sum(int *array, size_t len);
{
int c[len];
array = c;
}
void bar(void)
{
int x[] = { 1, 3, 5 };
size_t len = sizeof x / sizeof *x;
sum(x, sizeof x / sizeof *x);
printf("x[0] = %d, x[1] = %d, x[2] = %d\n", x[0], x[1], x[2]);
}
sum has only a copy of the pointer you've passed in bar, so from bar's
point of view, sum changed the copy, so bar will print
x[0] = 1, x[1] = 3, x[2] = 5.
But if you want that the caller sees any change, then you to access through the
pointer:
void sum(int *array, size_t len)
{
int c[len];
for(size_t i = 0; i < len; ++i)
array[i] += 10;
array = c;
}
With this version bar would print x[0] = 11, x[1] = 13, x[2] = 15 and
and array = c will have no effect on bar.
i want to dynamically add numbers to an array in c. My idea is to just allocate a new array with size + 1, add the number, free the root array and change the pointer from the temp to the root array. Like this:
void addNumber(int* a, int* size, int number)
{
*size = *size + 1;
int* temp = (int*)(calloc(*size, sizeof(int)));
int i, j = 0;
for(i = 0; i < *size-1; i++) {
if(a[i] < number) {
printf("add ai");
temp[j] = a[i];
j++;
} else {
printf("add number");
temp[j] = number;
}
}
if(j != *size) {
printf("add new number");
temp[j] = number;
}
free(a);
a = temp;
}
int main(int argc, char* argv[])
{
int n = 10;
int* a;
int size = 1;
a = (int*) (calloc(1, sizeof(int)));
a[0] = 1;
if(!contains(a, size, 2)) {
addNumber(a, &size, 2);
}
printArray(a,size);
return 0;
}
The problem is that in the addNumber function the code works and the *a has the right values of the new array. But in the main function the array *a has the values 1,0. So the new inserted value 2 is not added. Why? Can't get the reason.
To dynamically change the array size, you can use the realloc() routine. Apart from being eaiser to use, it can be faster than the approach of calling free() and malloc() sequentially.
It is guaranteed the reallocated block will be populated with the content of the old memory block.
The problem is that in the addNumber function the code works and the *a has the right values of the new array
There are two major flaws in your code. The first is that you your addNumber() routine doesn't return the newly allocated memory block (thus it is being leaked), you should either use double pointer or return the new block as function result.
And the second one results from the first - after a has been freed, you continue to write to it.
If you prefer to stick to your current approach, this modified code should work:
void addNumber(int** a, int* size, int number)
{
*size = *size + 1;
int* temp = (int*)(calloc(*size, sizeof(int)));
int i, j = 0;
for(i = 0; i < *size-1; i++) {
if((*a)[i] < number) {
printf("add ai");
temp[j] = (*a)[i];
j++;
} else {
printf("add number");
temp[j] = number;
}
}
if(j != *size) {
printf("add new number");
temp[j] = number;
}
free(*a);
*a = temp;
}
int main(int argc, char* argv[])
{
int n = 10;
int* a;
int size = 1;
a = (int*) (calloc(1, sizeof(int)));
a[0] = 1;
if(!contains(a, size, 2)) {
addNumber(&a, &size, 2);
}
printArray(a,size);
return 0;
}
What you're looking for is realloc(). It can be used to grow or shrink memory while retaining its contents.
/* array is now sizeof(int) * new_size bytes */
array = realloc(array, sizeof(int) * new_size);
realloc() might change the existing memory allocation, or it might allocate a whole new block of memory. This is why it's important to reassign the result back to the thing being reallocated.
But if addNumber() reallocates the array by making new memory, main() won't know it. This is for the same reason this doesn't work.
void incrementNumber(int num) {
num = num + 1;
}
int num is a number that gets passed by value. If you want it to be reflected in the caller, you need to pass it as a pointer.
void incrementNumber(int *num) {
*num = *num + 1;
}
Pointers are the same way. They're still numbers. int *a passes a pointer by value. If you change a in addNumber it won't be seen by the caller. Just like before, you need to pass it as a pointer. A pointer to a pointer used like this is known as a double pointer.
void addNumber( int **array_ptr, size_t *array_size, size_t type_size, int number ) {
/* Increment the size and make sure that bubbles up */
*array_size = *array_size + 1;
/* realloc might grow the memory, or it might allocate new memory
either way, assign the result back to its original variable
by dereferencing the double pointer.
*/
*array_ptr = realloc(*array_ptr, *array_size * type_size);
/* Since it's a double pointer, we have to first dereference it before using
it as an array */
(*array_ptr)[*array_size - 1] = number;
}
(Note that I also pass in the sizeof the elements in the array, that can't be assumed).
This is called by passing a pointer to the array.
addNumber(&a, &size, sizeof(int), 5);
After that, everything is the same.
for( int i = 0; i < size; i++ ) {
printf("%d ", a[i]);
}
puts("");
Eventually you'll want to improve this by having the array, size, and type in a struct so you can pass that around in a neat package.
typedef struct {
int *array;
size_t size;
} IntArray;
This is great to do as an exercise, you'll learn a lot and kick a lot of bad habits about static memory. But doing dynamic data structures correctly and efficiently is difficult (for example, allocating one extra slot at a time is very inefficient).
There are many, many libraries out there which provide such dynamic structures. So continue with this as an exercise, but for real code use a library such as Gnome Lib.
Why? Can't get the reason.
That's because you are modifying the value of a locally in addNumber. That does not change the value of a in main.
In order for main to have access to the newly allocated memory, you need to change addNumber to return the newly allocated pointer.
int* addNumber(int* a, int* size, int number){
...
return a;
}
and then change main to:
if(!contains(a, size, 2)){
a = addNumber(a, &size, 2);
// Assign to a the new pointer value.
}
Your 'a' in main is already a pointer, passing it to a function passes a copy of it. What you have to do is - pass the adress '&a' and receive it in funtion as double pointer '**a' and inside the function, use dereference to get values inside array ( like *a[i] and free(*a).
Change the last line to 'return temp' and collect it in main as a=addnumber(&a,&size,2);
By the way, instead of going through all these hassle why don't you just use realloc() function. It increases the size of array dynamically. After using realloc you can just add the new number at the last index.
int staticArrayA[10];
int staticArrayB[10];
int *dynamicArrayA = (int *)malloc(sizeof(int) * 10);
int *dynamicArrayB = (int *)malloc(sizeof(int) * 10);
From what I understand, the value of staticArrayA is a pointer to the 1st element in the array, however the pointer that represents this base address behaves like a const pointer and cannot be changed, in which case it makes sense that you cannot set:
staticArrayA = staticArrayB;
But what about dynamic arrays? if they are both just pointers to a contiguous block of bytes in memory, then why can't you set them equal to eachother?
dynamicArrayA = dynamicArrayB;
It seems like the address that dynamicArrayA points to would now be the same address that dynamicArrayB points to. Please give me some insight. Perhaps I am wrong, but here is what I was trying to do:
/* remove any element that is 0 from array. n is size of array */
void compressArray(int *array, int n) {
int size = n;
int index = 0;
int *nuArray = (int *)malloc(sizeof(int) * n);
assert(nuArray != NULL);
for (int i = 0; i < n; i++) {
if (array[i] != 0) {
nuArray[index] = array[i];
index++;
size--;
}
}
nuArray = realloc(nuArray, sizeof(int) * size);
assert(nuArray != NULL);
array = realloc(array, sizeof(int) * size);
assert(array != NULL);
array = nuArray; //This doesn't seem to work
free(nuArray);
}
int main(int argc, const char * argv[]) {
int *array = (int *)malloc(sizeof(int) * 10);
assert(array != NULL);
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
array[i] = 0;
} else {
array[i] = i;
}
}
compressArray(array, 10);
return 0;
}
I am sure that there are much simpler and more elegant ways to write the function, and i know that I can copy all the elements of nuArray into array and then use realloc() to reduce the size, however, I am just hoping someone can give some insight into the nature of dynamic arrays and explain some of this behavior and tell me why the assignment does not work, or if there are cases in which it does. Also, i could have the function return an int * and set array = to this function call and that works, however why can't i do it inside the function? Thanks for your time and for any help.
if they are both just pointers to a contiguous block of bytes in memory, then why can't you set them equal to each other?
Of course you can. You just have to know the ramifications.
int *dynamicArrayA = (int *)malloc(sizeof(int) * 10);
int *dynamicArrayB = dynamicArrayA;
Now dynamicArrayB and dynamicArrayA point to the same memory. You change the value of what one points to, the change will be visible through other pointer too.
dynamicArrayB[0] = 10; // dynamicArrayA[0] is 10.
dynamicArrayA[5] = 15; // dynamicArrayB[5] is 15.
If that's your objective, you can do that without any problem.
Update, in response to OP's comment
The line
array = nuArray; //This doesn't seem to work
changes the value of array locally in compressArray. That does not change the value of array in main.
You'll have to come up with a different method to return nuArray back to main.
One solution to the problem would be to change the return type of compressArray from void to char* and return nuArray from the function.
int *dynamicArrayA = (int *)malloc(sizeof(int) * 10);
int *dynamicArrayB = (int *)malloc(sizeof(int) * 10);
After this if you do this ( which ofcourse is possible ) -
dynamicArrayA = dynamicArrayB; //you want this then don't allocate memory to dynamicArrayA
Now , dynamicArrayA won't point to memory allocate by malloc to it previously , so you won't be able to free that memory block . Thus , can lead to memory leak.
You can use memcpy for this task -
/* allocate memory to both dynamicArrayA and to dynamicArrayB */
for(int i=0;i<10;i++){
dynamicArrayA[i]=i+1; // store value in dynamicArrayA
}
memcpy(dynamicArrayB,dynamicArrayA,sizeof(int)*10); //copy it to dynamicArrayB
for(int i=0;i<10;i++)
printf("%d",dynamicArrayB[i]); // print values
free(dynamicArrayA);
free(dynamicArrayB);
Let's take a look at what's actually happening at the end of compressArray:
array = nuArray;
After this statement, array now points to the same memory that nuArray points to. The memory that array previously pointed to is now accessible inside of compressArray, however array in main still points to the original memory block. That's because the address of this block is what was passed to compressArray, not the address of the array variable.
free(nuArray);
This frees the memory pointed to by nuArray. But since array contains the same value as nuArray, i.e. the address of the memory block pointed to by nuArray, now array points to a freed block of memory, and accessing it is undefined behavior.
When the function returns, the value of array in main is unchanged. That's because the value of array was passed in.
For this to work as expected, compressArray needs to take the address of a pointer (an int **) and change what that points to:
void compressArray(int **array, int n) { // "array" is a pointer to an array
int size = n;
int index = 0;
int *nuArray = (int *)malloc(sizeof(int) * n);
assert(nuArray != NULL);
for (int i = 0; i < n; i++) {
if ((*array)[i] != 0) { // note how we're now accessing the array
nuArray[index] = (*array)[i]; // same here
index++;
size--;
}
}
nuArray = realloc(nuArray, sizeof(int) * size);
assert(nuArray != NULL);
free(*array); // We don't need the memory array pointed to anymore, so free it
*array = nuArray; // This changes "array" in main. Also, don't free nuArray,
// otherwise *array will also point to freed memory
}
Then you call it like this:
compressArray(&array, 10);
// print the new contents of array
free(array); // We're done with it now, so free it