I have a function which is supposed to find min and max in an array using struct.
But somehow the function assigns wrong values to min and max variables. Could someone please explain where do I have the mistake? Thank you very much. P.S. In my assignment the function doesn't need to take the first element of the array
min_max_t min_max(unsigned int *array, int size)
{
min_max_t flag;
flag.min = array[1];
flag.max = array[1];
printf("Flag.min: %d | ", flag.min);
printf("Flag.max: %d\n", flag.max);
for (int i = 1; i < size; i++)
{
printf("i = %d - [A:%d - Min:%d - Max:%d]\n", i, array[i], flag.min, flag.max);
if(array[i] > flag.max)
{
flag.max = array[i];
}
else if (array[i] < flag.min)
{
flag.min = array[i];
}
printf("i = %d - [A:%d - Min:%d - Max:%d]\n\n", i, array[i], flag.min, flag.max);
}
return flag;
}
Screenshot of function process
There is nothing wrong with the logic for finding min and max.
The problem with your code is that you print unsigned int using %d. When printing unsigned int values use %u.
Another issue, that you may consider to handle, is illegal values of the function parameter size. Your function requires that size is at least 2. To avoid undefined behavior you may want to check for that.
In the start of the function you could for instance add
assert(size >= 2);
or
if (size < 2)
{
// return some suitable value
}
That said you can also just document the function to require size being at least 2. In C it's not uncommon to set such contract requirements for functions. Several stdlib functions have such requirements.
BTW: If you add check for size you should probably also check for array not being NULL.
BTW: Your Screenshot indicates that you pass an array of int to the function. If that's true then you have a bug in the caller-code. Don't pass an array of int to a function expecting an an array of unsigned int.
For starters the function should be declared like
min_max_t min_max( const unsigned int *array, size_t size );
and the structure min_max_t should contain two data members that will store indices to minimum and maximum elements. For example
typedef struct min_max_t
{
size_t min;
size_t max;
} min_max_t;
Otherwise the function can invoke undefined behavior when for example the user passed as the second argument 0.
Indices in arrays start from 0. So you skipped within the function the first element of the passed array.
As the array has elements of the type unsigned int then the expression -1 is converted implicitly to the maximum value of the type unsigned int. So you need to decide whether indeed you want to deal with unsigned integer arrays or with signed integer arrays.
Using the conversion specifier %d instead of %u in a call of printf to output an object of the type unsigned int can invoke undefined behavior if the value of the object does not fit in an object of the type int.
So your function can look the following way
typedef struct min_max_t
{
size_t min;
size_t max;
} min_max_t;
min_max_t min_max( const unsigned int *array, size_t size )
{
min_max_t flag = { .min = 0, .max = 0 };
printf( "Flag.min: %zu | ", flag.min );
printf( "Flag.max: %zu\n", flag.max );
for ( size_t i = 1; i < size; i++ )
{
printf( "i = %zu - [A:%u - Min:%u - Max:%u]\n", i, array[i], array[flag.min], array[flag.max] );
if ( array[flag.max] < arra[i] )
{
flag.max = i;
}
else if ( array[i] < array[flag.min] )
{
flag.min = i;
}
printf( "i = %zu - [A:%u - Min:%u - Max:%u]\n\n", i, array[i], array[flag.min], array[flag.max] );
}
return flag;
}
Related
Question
Use your function to change the contents of the array, i.e. multiply each number in the array by 2.
When your function has finished and your program continues in your main(), print the contents of your array in your main().
See if the changes made to the contents of the array in your function can be seen. If not, why?
Further
I'm trying to multiply the original array by 2 onto another array. Can anyone spot where I've went wrong?
#include <stdio.h>
#include <math.h>
#define SIZE 5
//function signatures
int getMultiples(int[]);
//main function
int main()
{
//main variables
int array[SIZE];
int multiples[SIZE];
printf("\nPlease enter 5 numbers into an array.\n");
for(int i = 0; i < SIZE; i++)
{
scanf("%d", &array[i]);
}
multiples[] = getMultiples(array);
printf("\nThis program will multiply all numbers by 2\n\n");
for (int i = 0; i < SIZE; i++)
{
printf("%d\n", multiples[i]);
}
return 0;
}
int getMultiples(int arr[])
{
//function variables
int i;
int multiples[SIZE];
for (i = 0; i < SIZE; i++)
{
multiples[i] = arr[i] * 2;
}
return multiples[];
}
This statement
multiples[] = getMultiples(array);
is syntactically and semantically invalid. This construction multiples[] is wrong and arrays do not have the assignment operator.
Also the definition of the function getMultiples is also wrong.
Again this statement
return multiples[];
is invalid.
What you are trying to do is to return the local array
int multiples[SIZE];
but the function return type is int. At least you needed to declare the return type as int *.
But in any case the local array that has automatic storage duration will not be alive after exiting the function.
If to use your approach then the function can look the following way
void getMultiples( int a1[], const int a2[], size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
a1[i] = 2 * a2[i];
}
}
and in main the function is called like
getMultiples( multiples, array, SIZE );
Pay attention to that the function definition should not depend on the magic number SIZE.
By the way in your assignment there is written
Use your function to change the contents of the array, i.e. multiply
each number in the array by 2.
It means that you need to change the source array,
In this case the auxiliary array multiples is redundant. The function could be defined the following way
void getMultiples( int a[], size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
a[i] *= 2;
}
}
and called in main like
getMultiples( array, SIZE );
You promise to return a single int.
int getMultiples(...);
You don't:
return multiples[];
You attempt to assign to a whole array (either a single int or an array....).
multiples[] = getMultiples(array);
That does not work in C.
And judging from what happens when trying your code, your compiler should have told you.
I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}
i want to find the size of a new array that's size is now reduced. But when i write the size function for new replaced array, it doesn't return the exact value it only returns size to n2 = 1 when it should be size n2 = 4.
#include <stdio.h>
void dupsRemove (int *arr, int n)
{
int i,newA[10],n2;
for (i=0; i<n; i++)
{
if (arr[i] == arr[i+1])
{
i++;
}
printf("%d ",arr[i]);
}
n2 = sizeof(arr)/sizeof(arr[0]);
printf("\n %d",n2);
}
int main()
{
int arr[]={1,3,3,2,5},i,j;
int n= *(&arr + 1) - arr;
dupsRemove(arr,n);
}
Once you pass the array into any function in C, the variable gets typecasted into one defined in the prototype of the function.
Inside the scope of dupsRemove(int *arr, int n), arr is of type (int *) whose size is given as sizeof(arr) = 8 or 4 depending on whether you are using a 64 bit or a 32 bit compiler respectively.
The only option to have the size of the array in function scope is to send the size of the array as an argument and change it accordingly when you modify the array.
I am trying to copy values from one array to another in C. The original array is of type long int, and it is inputted to the function as *pixel_frequency. The array I want to copy to is temp, and it is a 2D array. However, when I try to copy the values, pixel_frequency is fine but temp gives strange results. Below is the relevant code and some sample output.
Code:
struct node *generate_nodes(long int *pixel_frequency) {
int i;
int temp[max_value + 1][2];
for (i = 0; i < (max_value + 1); i++) {
temp[i][0] = i;
temp[i][1] = pixel_frequency[i];
printf("Frequency for %d is %d\n", temp[i][0], temp[i][1]);
}
...
Output (each frequency is supposed to be 256):
Frequency for 0 is 150160
Frequency for 1 is 256
Frequency for 2 is 256
Frequency for 3 is 256
Frequency for 4 is 255
...
Frequency for 254 is 892677956
Frequency for 255 is 1868789101
Below is an example version of code using your code snippet, take care of the return type and other things.
Instead of using a global variable for array size, you can pass it as a function argument so , it will be easy to identify the size of array you passed.
void generate_nodes(long int *pixel_frequency, size_t size) {
size_t i;
long int temp[size][2];
for (i = 0; i < size; i++) {
temp[i][0] = i;
temp[i][1] = pixel_frequency[i];
printf("Frequency for %ld is %ld\n", temp[i][0], temp[i][1]);
}
}
If you have declared pixel_frequency as a local variable in a function and used the address of array after the variable went out of scope, will lead to undefined behaviour.
int main(void) {
size_t max_len = 5000;
size_t i;
long int* pixel_frequency = malloc(max_len*sizeof(long int));
for( i = 0; i < max_len; ++i) {
pixel_frequency[i] = (i%256);
}
generate_nodes(pixel_frequency, max_len);
return 0;
}
I declare hws globally and try to return it in this method but I get a pointer error. I was wondering if anyone knew why that is and could suggest a solution? Randomize just get a random number.
extern int hws[100][20];
int randomize()
{
int value;
int tru_fals = 0;
value = -1;
while ( tru_fals != 1 )
{
value = rand();
if ( 0 < value )
{
if( 101 > value )
{
tru_fals = 1;
}
}
}
return value;
}
int *populate()
{
int i, j;
i = 0;
j = 0;
while( i < 20 )
{
while ( j < 100)
{
int temp = randomize();
hws[i][j] = temp;
j++;
}
i++;
}
return hws;
}
there is a bug: the array is declared as 100x20 but then you iterate through it like it is 20x100.
You define extern int hws[100][20];.
This doesn't create any array. It just says that somewhere in the program, there should be one.
To make it work, some other source file must really define the array - int hws[100][20]; (without extern). Then, if you compile both and link together, it should work.
If you only want one source file, it's much easier - just remove extern.
But: Just noticed Serge's answer, which is actually the real cause of the problem.
Except when it is the operand of the sizeof, _Alignof, or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and its value will be the address of the first element in the array (6.3.2.1/3).
In the line return hws; in populate, the type of the expression hws is "100-element array of 20-element array of int"; by the rule above, it will be converted to type "pointer to 20-element array of int", or int (*)[20]. Thus, the correct declaration for populate would need to be
int (*populate())[20]
{
...
return hws;
}
which reads as
populate -- populate
populate() -- is a function
*populate() -- returning a pointer
(*populate())[20] -- to a 20-element array
int (*populate())[20] -- of int.
and the type of whatever you return the result to would need to be int (*)[20] as well.
Having said that...
Using global variables this way is highly discouraged for a number of reasons. It would be better to pass the array in to populate as a parameter, like so:
void populate(int (*arr)[20], size_t rows)
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < 20; j++)
{
arr[i][j] = randomize();
}
}
}
You would call this as simply
populate(hws, sizeof hws / sizeof hws[0]);
If you're using a compiler that supports variable length arrays (either a C99 compiler or a C2011 compiler that does not define __STDC_NO_VLA__ or defines it to 0), you could define the function as
void populate(size_t cols, size_t rows, int (*arr)[cols]) // cols must be declared
{ // before it can be used
size_t i, j; // to declare arr
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i][j] = randomize();
}
}
}
and call it as
size_t rows = sizeof hws[0] / sizeof hws[0][0]; // dividing the size of the array
size_t cols = sizeof hws / sizeof hws[0]; // by the size of the first element
populate(cols, rows, hws); // gives the number of elements
so you're not hardcoding the 20 anywhere.
If you aren't using a compiler that supports variable length arrays, and you don't want to hardcode the number of rows in the function prototype, you can do something like this:
void populate(int *arr, size_t rows, size_t cols)
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i * rows + j] = randomize();
}
}
}
and call it as
// rows and cols calculated as above
populate(&hws[0][0], rows, cols);
In this case, instead of passing a pointer to the array, we pass a pointer to the first element (the address value is the same, but the type is int * instead of int (*)[20]. So the populate function treats it like a 1D array, and computes the offset with i * rows + j. Note that this trick will only work for 2D arrays that have been allocated contiguously.
This also means that populate can work with arrays of any size, not just Nx20.
hws is a matrix, it means that its and int **
You are returning and int * so you are having a pointer type mismatch.
First, it doesn't need to be returned since it's global. Second, it is a pointer to a pointer to an int. It's an array of an array.