C Macro for replacing array subscript - c

I want to replace array subscript of a C code with a call to a hash function. Is it possible to do this using a C macro?
This is an old code and it is very difficult to make changes to it. It will be very helpful, if I could just use a macro and a hash function instead of changing the actual code.
int array[1000];
// I want to define a macro such that array[idx] will be replaced with
// array[hash(idx)] and then define a function called hash(idx) which
// will return an integer within the bounds of the array (0..999)
int main()
{
int input;
scanf("%d", &input);
array[input] = 1;
return 0;
}

Related

How to pass each value of an array as parameters to a function?

I have the following function that accepts a varying number of integer parameters and returns the sum.
int sum(int a, ...){
va_list nums;
va_start(nums, a);
int res=0;
for(int i=0; i<a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
I need to pass each value of the array as a parameter to the function rather than passing the array itself. The array can be of varying length leading to a varying length of arguments to pass too.
printf("The sum is: %d", sum(size, args[0], args[1], ```need all elements of args[] array here```));
To put forth some perspective, I'm using this sum function to understand how I can go about doing this. It would be helpful to know how to achieve this in a more general setting rather than this exact function.
Please let me know if you need any more information.
Please do look at this question, which is similar, however, I require a solution in C.
The short answer is that there's no way to do exactly this in the C language. There is no ES6-like spread operator in C, nor similar functionality. I don't think there's any particular reason why they couldn't (you would just have to push more arguments onto the stack); they just never made one.
However, there are various other things you can do:
If variadic arguments were already passed into the function calling your function, you can pass along the va_list to a function declared to take a va_list. See Passing variable arguments to another function that accepts a variable argument list
As #JonathanLeffer suggests, the most natural way to write this code in C is by constructing an array of what "would be" your variadic arguments, and passing that into a function that expects an array (well, technically, a pointer, because arrays decay to pointers). For example:
int sum_array(int a, int nums[]){
int res=0;
for(int i=0; i<a; i++) {
res += nums[i];
}
return res;
}
In certain circumstances, it may be more convenient for a function like sum_array to take only the nums array/pointer, which would itself indicate the end of the array with a 0 or -1 value in the last slot. This is just another convention for indicating the end, which the caller has to set up.
You could then, if you really wanted to, write a variadic function that collects its arguments into an array and calls sum_array, if you want a variadic version as well. (Of course, you could also just implement the variadic and array versions separately, but for nontrivial functions it may be a pain to implement them twice.)
int sum_variadic(int a, ...){
va_list nums;
va_start(nums, a);
int arr[a];
for(int i=0; i<a; i++) {
arr[i] = va_arg(nums, int);
}
va_end(nums);
return sum_array(a, arr);
}
you could also use a variadic macro for the same purpose:
#define sum_macro(size, ...) sum_array(size, (int[]){__VA_ARGS__})
In summary: going from variadic to array in C is trivial, going from array to variadic is impossible.
You can also use extensions to the C language to do it anyway, as described in Passing a dynamic set of variadic arguments to a C function and In C, given a variable list of arguments, how to build a function call using them?, which #KamilCuk linked to.
You can avoid passing the number of arguments explicitly by using a variadic macro that constructs a compound literal array instead of a vararg function:
#include <stdio.h>
#define sum_int(...) (sum_int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int), (int[]){__VA_ARGS__})
int (sum_int)(size_t count, const int *a) {
int sum = 0;
for (size_t i = 0; i < count; i++) {
sum += a[i];
}
return sum;
}
int main() {
printf("sum = %d\n", sum_int(1, 2, 3));
return 0;
}
This approach can be used for any purpose, as long as the types of the variable arguments are converted implicitly to the array type.
If you want to pass just the arguments to your sum function without changing its definition, you can use a variation of the macro:
#include <stdio.h>
int sum(int a, ...) {
va_list nums;
va_start(nums, a);
int res = 0;
for (int i = 0; i < a; i++) {
res += va_arg(nums, int);
}
va_end(nums);
return res;
}
#define sum(...) (sum)((int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int)), __VA_ARGS__)
int main() {
printf("sum = %d\n", sum(1, 2, 3));
return 0;
}
Note however that there is no type checking with this approach and sum(1, 2.0, 3) would have undefined behavior.

Can macro in c generate serialized statement? [duplicate]

I want to generate an array initializer with arbitrary logic that unfortunately requires some looping.
#define RANDOM_ARRAY(n) \
...
double array[] = RANDOM_ARRAY(10);
Suppose the code above generates an initializer for a 10-element array. Is it possible to define such a macro (with a loop) in C99 ?
NB: it doesn't have to be a macro if a function call could suffice (but it has to be possible to call it among global initializers, not in a second function);
Unfortunately, it is not possible to create a recursive (or loop) macrofunction in C. Nevertheless, if you have a reasonable maximum length for your initializer, you can use this type of construct :
#define INITIALIZER(N) { INITIALIZER_ ## N }
#define INITIALIZER_1 1
#define INITIALIZER_2 INITIALIZER_1, 2
#define INITIALIZER_3 INITIALIZER_2, 3
int
main(void)
{
int tab[3] = INITIALIZER(3);
return 0;
}
The C preprocessor doesn't support loops, so what you want is not (easily) possible.
I added the '(easily)' because there are ways to get loop-like behavior using something like boost's ITERATE. This uses recursive file inclusion to emulate a loop. But I'm not sure if you want to go that far.
Since you're working in C99, you can of course create a macro that does the initialization, but you won't be able to make it look like an initializer:
#define INCREMENTING_ARRAY(t,a,n) t a[n]; do {\
for(size_t i = 0; i < n; ++i)\
a[i] = i;\
} while(0);
This creates an array whose elements are initialized to be incrementing, as an example.
Usage:
int main(void)
{
INCREMENTING_ARRAY(int, dozen, 12);
int i;
for(i = 0; i < sizeof dozen / sizeof *dozen; ++i)
printf("array at %d = %d\n", i, dozen[i]);
return 0;
}
This works since in C99 you can freely mix declarations and code, so the int i; after the macro usage is fine. In C89, it wouldn't have worked.

C callback function argument scope

H.ello just a hobbyist here. I started again C after a little JS detour that taught me closures, oop and other stuff. I usually make small code snippets that I can reference or reuse later. So in the code below is there a reason why the compiler says counter is undeclared, as it is referenced as an argument of the callback function argument?
To make this work,
1. I could make counter a global variable, this works but it is not best practice.
2. I could move caller function inside main, but I'd like to avoid this.
3. pass counter as a 4th seperate pointer argument, however in that case, I don't really know with what voodoo should I invoke the caller function popArr within main.
Generally I'm interested in the technique how to use callbacks with arguments without using global variables or putting everything inside main.
So here is the code:
#include <stdio.h>
// CALLBACKS
/* Caller */
void popArr(int *arr, size_t length, int (*callback)(int *counter)) {
for (size_t i=0; i<length; i++) {
arr[i] = callback(&counter);
printf("arr[%zu] is: %d\n", i, arr[i]);
}
}
/* A simple generator callback saving counter. */
int generator(int *counter) {
*counter = *counter+1;
return *counter*5;
}
/* Main function. */
int main(void) {
int counter = 1;
int arr[10];
popArr(arr, 10, &generator);
return 0;
}
So in the code below is there a reason why the compiler says counter
is undeclared, as it is referenced as an argument of the callback
function argument?
I presume you mean in function popArr(). Yes, of course there's a reason. In popArr(), the symbol counter appears only in the prototype for the callback function, and the scope of that appearance is limited to the prototype in which it appears. There is no symbol with that name in scope in the body of popArr().
The different appearances of the symbol counter in that prototype, in function generator(), and in main() all have different, non-overlapping scope. They are not related to each other, notwithstanding the reuse of the same name.
Generally I'm interested in the technique how to use callbacks with arguments without using global variables or putting everything inside main.
There are two main scenarios:
Callbacks with parameters that the caller (popArr() in your example) is expected to choose itself, and
Callbacks with parameters that the callback provider (main() in your example) is expected to specify.
Those are not mutually exclusive. Case (1) has no special requirements -- the caller just passes whatever argument is appropriate, at its own discretion. Case (2) isn't much harder, in principle: the code that provides the callback simply needs to provide the appropriate argument with it. For your very simple case, where the argument and callback do not need to be stored, that would look something like this:
void popArr(int *arr, size_t length, int (*callback)(int *), int *counter) {
// The name of the parameter to (*callback)() is omitted for clarity. It is
// optional in this context.
for (size_t i = 0; i < length; i++) {
arr[i] = callback(counter); // Note: passing counter, not *counter
printf("arr[%zu] is: %d\n", i, arr[i]);
}
}
/* A simple generator callback saving counter. */
int generator(int *counter) {
*counter += 1;
return *counter * 5;
}
/* Main function. */
int main(void) {
int counter = 1;
int arr[10];
// It is unnecessary, but not harmful, to use the & operator on the function
// name. I think it's better style to omit it.
// It is necessary to use the & operator on 'counter', but mainly because
// you want to pass a pointer to counter, as opposed to its value
popArr(arr, 10, generator, &counter);
return 0;
}

Enum/Dictionary-Like Tool in C?

I'm reading over a solution to a problem in K&R's chapter 7 posted here. Basically, the program will convert the standard input into lowercase or uppercase depending on the name of the program ("upper" or "lower"). It seems to store the names of the conversion functions in some kind of dictionary, like so:
int (*convcase[2])(int) = {toupper, tolower};
and later access these functions depending on whether the name of the program started with a u or an l:
if(argc > 0)
{
if(toupper((unsigned char)argv[0][0]) == 'U')
{
func = 0;
}
else
{
func = 1;
}
while((ch = getchar()) != EOF)
{
ch = (*convcase[func])((unsigned char)ch);
putchar(ch);
}
}
I understand what that code block is doing, but I've never seen anything like the initial declaration of convcase. It seems like some kind of weird combination of a macro, an enum, and an array. Could anyone explain (1) why convcase is a pointer; (2) what's with the (int) cast after its name; (3) what exactly toupper and tolower are within that declaration, because they're not char *s; and (4) when/why to use this kind of setup. Is it just a quick macro-like tool to save some space when you have multiple possible function calls?
convcase is an array of two function pointers; It's not a pointer. An array expression will be implicitly converted to a pointer when it is used in a place where a pointer is expected.
That's not a cast. It's specifying that the functions accept an int argument, as the toupper and tolower functions do.
convcase is initialised with the function pointers toupper and tolower.
I presume this question is regarding function pointers. Use function pointers when you wish for the abstraction of function pointers. I'd suggest that this example is an unnecessary use of function pointers. The ability to change convcase[0] or convcase[1] to Spanish or Japanese, depending upon user input would more likely warrant the use of function pointers in this case. Additionally, function pointers could be used in arguments to provide additional abstraction. For example, the qsort function is able to sort arrays of any type because of it's usage of function pointers for a comparer of objects. Here's an example that sorts int input using the int_compare function as the comparer.
#define nelem(array) (sizeof (array) / sizeof *(array))
int int_compare(const void *p1, const void *p2) {
int x = *(int *)p1, y = *(int *)p2;
return (x > y) - (y > x);
}
int main(void) {
int value[16];
for (size_t x = 0; x < nelem(value); x++) {
if (scanf("%d", &value[x]) != 1) {
break;
}
}
qsort(value, sizeof *value, x, int_compare);
return 0;
}

All the array length methods in C don't work

I have tried (sizeof(array)/sizeof(array[0])). Didn't work.
I wrote a simple function:
int length(int array[]){
int i=0;
while(array[i]) i++;
return i;
}
Worked one minute, didn't work the next.
Someone please help! I'm using Xcode as an IDE
The length of an array is not part of the array in C, so when passing an array as a parameter to a function you should pass its length as a parameter too. Here's an example:
#define ARRLEN(a) (sizeof(a)/sizeof (a)[0]) /* a must be an array, not a pointer */
void printarray(int* a, int alen)
{
int i;
for (i = 0; i < alen; i++)
printf("%d\n", a[i]);
}
main()
{
int a[] = { 3, 4, 5 };
printarray(a, ARRLEN(a));
return 0;
}
However, if your array is defined in such a way as to always end with a sentinel that isn't normal data, then you can traverse the elements until you encounter the sentinel. e.g.,
void printstrings(char** a)
{
int i;
for (i = 0; a[i]; i++)
printf("%s\n", a[i]);
}
main()
{
char* a[] = { "This", "should", "work.", NULL };
printstrings(a);
return 0;
}
Passing an array into a function is the same as passing a pointer to the array.
So sizeof(array)/sizeof(array[0]) does not work.
You can define a global macro:
#define A_LEN(a) (sizeof(a)/sizeof(a[0]))
Try this
main()
{
int a[10] ;
printf("%d\n", sizeof(a)/sizeof(int) ) ;
}
output : 10
See Why doesn't sizeof properly report the size of an array when the array is a parameter to a function? from the comp.lang.c FAQ to understand why the sizeof method doesn't work. You probably should read the entire section on arrays.
Regarding your length function, your "simple" function can work only if your array happens to have the semantic that it is terminated with an element that has the value of 0. It will not work for an arbitrary array. When an array has decayed into a pointer in C, there is no way to recover the size of the array, and you must pass along the array length. (Even functions in the C standard library are not immune; gets does not take an argument that specifies the length of its destination buffer, and consequently it is notoriously unsafe. It is impossible for it to determine the size of the destination buffer, and it therefore cannot prevent buffer overflows.)
There are several methods to get the length of array inside a function (can be in the same file or in different source file)
pass the array length as a separate parameter.
make array length as global extern so that function can directly access global data

Resources