I'm writing some Code that does some basic analysis on data.
The data collected is in an array of structs. It takes the approximate form:
struct page {
int width;
int length;
char name[50];
// etc...
}
struct page pages[100];
I need to write code that finds the smallest width, largest width, smallest length, largest length, etc. So I write code that looks something like this:
int smallestWidth(struct page pages[]){
unsigned int smallest = -1;
(for loop){
if (smallest > pages[i].width) smallest = pages[i].width;
}
return smallest;
}
And then I find that I'm copy-pasting this function and changing tiny details for the other requirements like largest width. And whenever I'm copy-pasting chunks of code, that raises alarm bells for me, and I'm thinking I'm doing it wrong.
But, I'm kind of new to C, so I'm not sure what the right way to approach this is.
How would you write this in C properly (if there is a proper way) that minimizes the amount of code that I'm copy-pasting?
C++ language has overrides and pointer to members that C has not. So the C way would be to use auxilliary functions to extract the correct data and compare them:
int getLength(struct page *page) {
return page->length;
}
int getWidth(struct page *page) {
return page->width;
}
int lesser(int a, int b) {
return a<b;
}
int greater(int a, int b) {
return a>b;
}
typedef int(*extractor)(struct page *p);
typedef int (*comparator)(int a, int b);
int process(struct page * p, int size, extractor ext, comparator cmp) {
// code here the generic part
...
}
int lesserWidth = process(pages, 100, &getWidth, &lesser);
...
But it includes a good deal of boiler plate code, so it may be interesting or not depending on the complexity of the generic part...
I think the following will be classified as a Horrible Hack, however, it satisfies your request. It only works for integers because of the compare.
struct page {
int width;
int length;
// etc...
} pages[100] = {{1,2},{3,4},{5,6}};
int smallestX(struct page pages[], size_t offset)
{
unsigned int smallest = -1, k;
for (int i=0; i<3; i++){
k= *((int *)((char *)(&pages[i])+offset));
if (smallest > k) smallest = k;
}
return smallest;
}
void example(void)
{
printf ("smallest width= %d\n", smallestX(pages, offsetof(struct page, width)));
printf ("smallest length= %d\n", smallestX(pages, offsetof(struct page, length)));
}
Clarification:
It uses the offsetof macro to get the offset of the member from the beginning of the struct. In the function, it now takes the address of the ith element of the array, interprets that as a byte address, adds the offset (which is in bytes), interprets that as a pointer to an int, dereferences that int and uses it in the compare.
Note: it is possible to extend this method to compare any item by providing a compare function as parameter.
Related
I have no idea what to do. Whenever I try to insert read_num[size] it does not work. My debugger shows the value as 0. I want to take a value for the size of the array from the user. Then I want to use the value in another file.
So what I want to do is, I will do a printf to ask the user to give a value so that I can pass it as the size of the array. I did and it didn't work. Then I decided to write a direct value [36]. But I want user to insert 36.
This is what I have tried:
main.c
int main(void)
{
int numbers[ARR_SIZE] = { 0 };
int size = 36; // I am doing directly but I want to take the value from the user but it just does not work.
double mean = 0;
double stddev = 0;
read_array(size);
}
file.c
int read_array(int a[36]) //placing 36 directly, I want it to be placed by the user
{
int num_read[36]; int i = 0; // I have no clue whats i am doing. I just want to pass the value from the user.
while (i < a)
{
printf("Enter number");
scanf_s("%d", &num_read[i]);
++i;
}
}
header file
#include <stdio.h>
#include <math.h>
#define ARR_SIZE 100
int read_array(int arr[ARR_SIZE]);
double calc_mean(int arr[], int size);
double calc_stddev(int arr[], int size);
void print_array(int arr[], int size);
In you main.c file you want to decide the value of size and use that value in a call to the function read_array().
You do so by calling read_array(size);, which makes sense to me.
Sadly your shown code lacks the details of whether or not you include your header file (and others). I assume that it does.
However, if what you are doing inside main() is actually what you want to do (I assume so), then the header file and the implementation of read_array() does not match that intention.
This int read_array(int arr[ARR_SIZE]), in your header and your implementation, means
"Dear compiler, this function takes an array (or a pointer to 100 consecutive ints)."
That does not match your plan of "I will give a single int as the parameter to the function."
To match that plan, use a prototype of int read_array(int a);.
The implementation code as shown should then work.
If you want the local array to actually be of the size given by the user and arriving via the parameter a, then change
int num_read[36]; to int num_read[a];.
However, I suspect that you then intend to return the array which you filled with input from the user.
That is neither possible with a prototype of int read_array(int a); nor with one of int read_array(int arr[ARR_SIZE]);. Both mean "This function will return a single int.".
I assume you will need help with that, but you need to ask a separate question on how to return a new array from a C function - or better first search StackOverflow for a duplicate.
To pass the size of the array to the function (it does not matter if it is defined in the same or another compilation units) you need to have an additional parameter to the function. There is no other way of doing it in C language
int *doSomethingWithArray(int *array, size_t size)
{
/* ... */
}
But I want user to insert 36.
The user can only enter something using I/O functions and has no access to the C code.
int *initArray(int *array, const size_t size)
{
for(size_t index = 0; index < size; index ++)
array[index] = rand();
return array;
}
int *printArray(int *array, const size_t size)
{
for(size_t index = 0; index < size; index ++)
printf("array[%3zu] = %d\n", index, array[index]);
return array;
}
int main(void)
{
size_t array_size;
srand(time(NULL));
if(scanf("%zu", &array_size) == 1) // user enters the size of the array
{
int array[array_size];
initArray(array, array_size);
printArray(array, array_size);
}
}
https://godbolt.org/z/xjh9qGcrz
I am still learning about C programming, and I am having a bit of an issue with my program.
So my structure is declare in q.h file
#define MAXIMUM_LENGTH 80
struct Tsunami {
unsigned int day;
unsigned int month;
unsigned int year;
unsigned fatalities;
double height;
char location[MAXIMUM_LENGTH];
};
and the function that uses qsort is :
double get_median_height(const struct Tsunami* begin, size_t count)
{
double median = 0;
double compare1,compare2;
struct Tsunami* store = (struct Tsunami*) malloc (sizeof(struct Tsunami) * count);
for (int i = 0; i < (int)count; i++)
{
store[i].month = begin[i].month;
store[i].day = begin[i].day;
store[i].year = begin[i].year;
store[i].fatalities = begin[i].fatalities;
store[i].height = begin[i].height;
strcpy(store[i].location, begin[i].location);
}
qsort(store, count, sizeof(Tsunami), compare_events);
if(count % 2 == 0)
{
printf("%ld",count);
compare1 = store[(count/2)].height;
printf("%lf",compare1);
compare2 = store[(count/2) +1].height;
printf("%lf",compare2);
median = (compare1 + compare2)/2;
}
else
{
median = store[(count/2)].height;
}
free(store);
return median;
}
My compare_events code is
int compare_events(const void* first, const void* second)
{
struct Tsunami* first = (struct Tsunami*)first;
struct Tsunami* second = (struct Tsunami*)second;
return (second->height - first->height);
}
For some reason, it does not help me sort out the value of store.height from smallest to largest. Can someone explain to me why? and how should I use the qsort instead?
Your comparison function:
Is backwards. It's supposed to return a number less than zero if first < second, but yours does the opposite. So intuitively it should be return first->height - second->height. However...
As "chux - Reinstate Monica" alluded to in comments, your heights are of type double but the comparison function must return int. So your function implicitly converts their difference to an int, but this conversion always rounds toward zero. Thus any two heights that differ by less than 1 will have a difference less than 1, which will be rounded to zero and qsort will think the two Tsunamis are of equal height, and may put them in the array in any order.
What you really want is something like sign(first->height - second->height). Unfortunately C has no standard sign function, but you can find many possible implementations at Is there a standard sign function (signum, sgn) in C/C++?. (This will also fix another bug, which is that your function will not correctly compare heights whose difference doesn't fit in an int.)
I'm passing an array of single-precision floating point values to a function in C. The function has no knowledge of the size of the array and I'd like to keep it that way, primarily because while the underlying array is of course fixed-length I won't always be filling it completely so I'd need to be able to find the end anyway. With a string you use a null-terminator, but with this implementation all possible values are potentially valid. Is the best I can do like a "code word" to mark the end using multiple values in order, something like ASCII 'STOP'? That leaves open the possibility of coincidentally having that code word in the array of valid data...
You'll see array/size pairs being passed around in C a lot, it's really the only way to do this reliably. Even C strings, which are NUL terminated, are often sent with a length parameter to be sure you don't inadvertently walk off the end of the array and into other memory.
This approach also permits you to use substrings, or subsets of the array, instead of being committed to use the whole thing, the problem you're basically trying to solve. Having a terminator is both a blessing and a curse, as anyone who's ever tried to battle a pernicious buffer-overflow bug can attest to.
In your case, the function signature should look like:
void process(float* v, size_t n)
Where v is the array of floating-point values to process and n is how many of them to use. n should be less than or equal to however many valid entries are in the v array.
If you're passing this kind of thing around a lot you may even encapsulate it in a simple struct that defines the data and size. You can then wrap around that some simple allocator/populator tools.
For example:
struct float_array {
float* values;
size_t size;
};
Where you can then define something like:
struct float_array* make_float_array(size_t n);
void free_float_array(struct float_array* f);
You don't need to pass the array maximum length, just the length currently being used for this call along with the pointer.
You can use NAN this way, assuming that's not a valid value for your dataset:
#include <math.h>
float average(float *array)
{
float sum = 0.0; // Declare this as double for better precision
size_t index = 0;
// x == NAN will return false for all x including NAN, so we need
// the function isnan()
while(! isnan(array[index]))
sum += array[index++];
return sum/index;
}
Since you're probably want to do this for many functions, I recommend writing a function for calculating length:
size_t farray_length(float *array)
{
size_t len = 0;
while(! isnan(array[len])) len++;
return len;
}
But the usual way of solving these problems in C is to send the size as a separate parameter.
float average(float *array, size_t size)
{
float sum = 0.0;
for(size_t i=0; i<size; i++)
sum += array[i];
return sum/size;
}
A third way, which can be useful for instance if you're coding a library with objects you don't want the user to mess with directly, is to declare a struct.
struct float_array {
float *array;
size_t size;
}
float average(float_array array) {
...
With a string you use a null-terminator, but with this implementation all possible values are potentially valid.
If all values are valid, a sentinel value cannot be implemented. It's as simple as that (which is why EOF is an integer value that overflows the char type).
The function has no knowledge of the size of the array and I'd like to keep it that way...
Assuming NaN is an invalid value, you could use the isnan() macro to test for a sentinel value.
However, is NaN is a valid value...
I'd need to be able to find the end anyway.
The only option left is to actually pass the array length along with the array.
If you can't add the array length as a separate argument, you could (probably) store the length of the array as the first member - either using a struct (recommended) or using type punning (don't try this at home unless you know what you're doing).
i.e.
typedef struct float_array_s {
unsigned int len;
float f[];
};
static unsigned int float_array_len(float_array_s * arr) { return arr->len; }
static float float_array_index(float_array_s * arr, unsigned int index) { return arr->f[index]; }
There's really no reason to use computation cycles if you can simply pass the length of the valid array length along with the array.
Edit (type punning)
I highly recommend avoiding this approach, since type lengths could cause hard to detect bugs. However...
It's possible to store the length of the array in the first float member, by using the same bytes (memory) to store an integer.
Note that this might crash (or worst, silently fail) if unsigned int is longer than float (which it might be, even though they usually have the same size in bytes).
i.e.
#include "math.h"
#include "stdint.h"
#include "stdio.h"
/* Returns the member at `index`. */
static float float_array_index_get(float *arr, unsigned int index) {
return arr[index + 1];
}
/* Sets the member at `index` to `val. */
static void float_array_index_set(float *arr, unsigned int index, float val) {
arr[index + 1] = val;
}
/* Returns the array's length. */
static unsigned int float_array_length_get(float *arr) {
if (sizeof(unsigned int) > sizeof(float)) {
fprintf(
stderr,
"ERROR: (%s:%d) type size overflow, code won't work on this system\n",
__FILE__, __LINE__);
}
union {
float f;
unsigned int i;
} pn;
pn.f = arr[0];
return pn.i;
}
/* Sets the array's length. */
static void float_array_length_set(float *arr, unsigned int len) {
if (sizeof(unsigned int) > sizeof(float)) {
fprintf(
stderr,
"ERROR: (%s:%d) type size overflow, code won't work on this system\n",
__FILE__, __LINE__);
}
union {
float f;
unsigned int i;
} pn;
pn.i = len;
arr[0] = pn.f;
}
/* Pushes a member to the array, increasing it's length. */
static void float_array_index_push(float *arr, float val) {
unsigned int len = float_array_length_get(arr);
float_array_index_set(arr, len, val);
float_array_length_set(arr, len + 1);
}
/* Pops a member from the array...
* ... returning nan if the member was nan or if the array is empty.
*/
static float float_array_index_pop(float *arr) {
unsigned int len = float_array_length_get(arr);
if (!len)
return nan("");
float_array_length_set(arr, len);
return float_array_index_get(arr, len);
}
P.S.
I hope you'll stick to the simple func(float * arr, size_t len) now that you see how much extra code you need just to avoid passing the length of the array.
I was reading over some of the source code behind pngquant (here)
I got confused when I saw plus-equals seemingly assigning a new value to an array of structs (base += r in the code snippet below):
static void hist_item_sort_range(hist_item base[], unsigned int len, unsigned int sort_start)
{
for(;;) {
const unsigned int l = qsort_partition(base, len), r = l+1;
if (l > 0 && sort_start < l) {
len = l;
}
else if (r < len && sort_start > r) {
base += r; len -= r; sort_start -= r;
}
else break;
}
}
The hist_item definition is given as:
typedef struct {
f_pixel acolor;
float adjusted_weight, // perceptual weight changed to tweak how mediancut selects colors
perceptual_weight; // number of pixels weighted by importance of different areas of the picture
float color_weight; // these two change every time histogram subset is sorted
union {
unsigned int sort_value;
unsigned char likely_colormap_index;
} tmp;
} hist_item;
I apologize ahead of time, because I'm sure to those in the know this must be a really dumb question, but how is plus-equals operating on base, which appears to be an array of structs, and some integer r? It seems to me that this operation should be undefined for the combination of those two types.
I haven't had to write C for almost ten years, and I'm admittedly pretty rusty; however, searching for about thirty minutes only turned up answers to the wrong questions, and any help is appreciated. Thanks!
As explained in What is array decaying?
static void hist_item_sort_range(hist_item base[], unsigned int len, unsigned int sort_start)
becomes
static void hist_item_sort_range(hist_item* base, unsigned int len, unsigned int sort_start)
Where base is a pointer to the first element of the array. Therefore base += r; performs simple pointer arithmetic, i.e.: modifies the pointer to point to an offset of r elements from the start of the array.
Due to the += the original pointer is modified, so any access happens with offset from the now pointed to element.
To use the example from the comment:
After base += 1; accessing the "first" element via &base[0]; yields a pointer to the same element as &base[1]; before the increment
I'm following LCTHW tutorial and I have a task to do.
This is the data structure:
typedef struct DArray {
int end;
int max;
size_t element_size;
size_t expand_rate;
void **contents;
} DArray;
I have declared a typedef:
typedef int (*DArray_compare) (const void *a, const void *b);
When I create a sorting function, I pass to it a DArray_compare, the problem is that I can't figure out how to do an example of this comparator.
I tried to do something like this:
int compare(const void *a, const void *b)
{
int i = (int)*a;
int k = (int)*b;
printf("%d %d\n", i, k);
return i - k;
}
But I get an error:
error: operand of type 'void' where arithmetic or pointer type is required int i = (int)*a;
The question is: without changing the struct and the typedef of the comparator, I want to create a comparator that compares int, how can I do it?
int i = *(int*)a;
// This one has more parens to make it really obvious what your intent is.
int k = *((int*)b);
The second line (k=) is easiest to explain cos of all the brackets. You can rewrite it as follows:
// Cast b from a pointer to a void into a pointer to an int.
int *X = (int*)b;
// k = "what X is pointing to" or "the contents of X"
int k = *X;
edit:
I think ralu's comment is suggesting you change all the void* to int* which is a much safer solution if you have that power.
typedef int (*DArray_compare) (const int *a, const int *b);
int compare(const int *a, const int *b)
{
int i = *a;
int k = *b;
...
A comparison function for use with bsearch() or qsort() from the standard C library for arrays of DArray structures might look like:
int compare(const void *a, const void *b)
{
const DArray *d1 = a;
const DArray *d2 = b;
if (d1->end < d2->end)
return -1;
else if (d1->end > d2->end)
return +1;
else if (d1->max < d2->max)
return -1;
else if (d2->max > d2->max)
return +1;
else
return 0;
}
Clearly, if you need to compare other fields, you can add those comparisons into the framework above quite easily. The general structure of the function is my recommended way of writing such comparators. You can add explicit casts to the assignment lines if you wish; C++ would require them, but C does not.
Note that your typedef is of minimal relevance to the comparator itself (though the comparator as a function pointer should match that typedef). It is the type that a comparator should have, but you can't use that typedef name when writing the function. You could use the typedef in the implementation of the sort function and in its declaration.
I observed in a couple of places that returning the difference of two signed int values as the result of the comparator leads to undefined behaviour.
In a comment to a now deleted answer, AR89 asked:
Instead of the subtraction an if statement would be safer?
Yes. Consider what happens if you have 16-bit int values and you compare -30,000 and +30,000; you've got signed overflow, and you might get a positive value back from your comparator, even though the first value is less than the second. Analogous situations can occur with 32-bit or 64-bit integers. They're relatively unlikely; if you know that your values are well within range, you'd be OK. But for general purpose code, you should do the piecewise comparison:
if (i < k)
return -1;
else if (i > k)
return +1;
else
return 0;
as it works regardless of the values of i and k. Also note that the if comparison works reliably for unsigned int types too, whereas subtraction really doesn't work then (the result is always zero or positive).