Token pasting in c using a variable that increments - c

I have a set of arrays :msg1[] msg2[] .... msgn[] . And I need to use the values in a while loop. as msgi[]. When I define it as #define MSG(a) msg##a
and put it in a loop and increment i, it expands it to msgi?

You can't do it that way. Instead you could create a new array, that contains pointers to the actual arrays:
int array1[...];
int array2[...];
int *all_arrays[] = { array1, array2 };

build your c code with gcc -E myfile.c and you will see the reason
this called preprocessor code. the prprocessor code is the code generated by your compilator before the compilation. in this code the compilator replace the macros in your origin code with the content of the macro.
your origin code:
for (i=0; i<10; i++) {
for (j=0; j<10; j++)
MSG(i)[j] = 3;
}
preprocessr code generated from the origin code (could be seen with gcc -E):
for (i=0; i<10; i++) {
for (j=0; j<10; j++)
msgi[j] = 3;
}
You can use 2D array instead
int msg[5][5];

It can't be done cause macros are replaced at compilation time not runtime, so it will be replaced once...
what you could do is use 2D array if there are in the same size or use array of arrays if there are in different sizes:
//once in your code you need to do this:
int array0[];
int array1[];
//...
int arrayX[]; //X should be replaced with a real number...
int **arrayOfArrays = new (int*)[X+1];
arrayOfArrays[0] = array0;
arrayOfArrays[1] = array1;
//...
arrayOfArrays[X] = arrayX;
//now you could use it like that anytime in your code:
int i;
for(i = 0; i < X; ++i)
{
//Do whatever you want to do, like:
arrayOfArrays[i][0] = 1234;
}

When I define it as #define MSG(a) msg##a and put it in a loop and
increment i, it expands it to msgi?
No, it will not work that way, because the macro gets expanded before compilation, not after. You'll need a different approach, such as the 2D array suggested by #zakinster.

No, unfortunately it won't. C does not support runtime name lookups. Instead, you should use a two dimensional array of the form:
void** msg;
This will allow the arrays to be of different sizes and types, although you will have to cast to whatever type the array is.

Related

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: howto convert a pointer to access it as a multidimensional array

I do have a function call like:
int Filter(short* array, short nNumRow, short nNumCol)
but inside it I want to handle array like that:
array[y][x] = xx;
I try to solve this by declaring an array
short help[nNumRow][nNumCol];
help = array;
but this doesn't work that way. How can I handle that problem without changing function parameter list (this *array is result of a different function that I can't change)? Best of course would be not a copy (of memory) is needed.
Probably another option would be
array[y*nNumCol + x] = xx;
but I don't like this calculations. So how to do this best?
Thanks!
How can I handle that problem without changing function parameter list?
If you can't do that, then you are stuck with the "mangled array" array[y*nNumCol + x] notation (which is old style but otherwise ok).
The best and correct solution is to change the function to this:
int Filter (short nNumRow, short nNumCol, short array[nNumRow][nNumCol])
{
...
array[x][y] = something;
}
The last resort, which I would not recommend unless you are maintaining some old crap that can't be changed, is a dirty pointer conversion inside the function. Writing such code requires that you to know exactly what you are doing, because if the types of the actual data or the alignment mismatch, you will get very strange bugs. The below code works and is safe as far as the C language is concerned, but it isn't pretty:
// BAD CODE, avoid this solution
#include <stdio.h>
int Filter (short* array, short nNumRow, short nNumCol)
{
short(*array2D)[nNumCol]; // pointer to array of type short[nNumCol]
array2D = (short(*)[nNumCol])array; // dirty pointer conversion
for(int i=0; i<nNumRow; i++)
{
for(int j=0; j<nNumCol; j++)
{
printf("%d ", array2D[i][j]);
}
printf("\n");
}
return 0;
}
int main (void)
{
short array[2][2] = { {1,2}, {3,4} };
Filter((void*)array, 2, 2);
}
The best (optimal) way to do that is your own solution:
array[y*nNumCol + x] = xx;
Fo "beauty" reasons, you may use a function-like macro to access that data:
#define arrElement(array,x,y) ((array)[(y)*nNumCol + (x)]]))
If you need to apply this trick to only one array, then you can simplify the macro:
#define arrElement(x,y) (array[(y)*nNumCol + (x)]]))
If the size of the array is not known before the function call, you will need to add some complexity to the macro:
#define arrElement(x,y,nNumCol) (array[(y)*(nNumCol) + (x)]]))
Note: I did not text exactly the statements above, but I used the trick in the past several times, successfully.
You can use a pointer-type (as per your question) only if the array always has the same size. Otherwise, you will have to define the pointer-type dynamically at run-time, which is somewhere between difficult and impossible.
A sane thing to do is to pass to the function the array size also, and check if the coordinates actually fall inside the array. Otherwise, you may run into undefined behavior, accessing data outside defined range.
Not the most efficient way, but you can create a two dimensions array inside your function and copy the original array to it:
#include <stdio.h>
int Filter(short* array, short nNumRow, short nNumCol) {
short arr[nNumRow][nNumCol];
memcpy(arr, array, nNumRow * nNumCol * sizeof(short));
for (int i = 0; i < nNumRow; i++) {
printf("| ");
for (int j = 0; j < nNumCol; j++) {
printf("%d ", arr[i][j]);
}
printf("| \n");
}
return 0;
}
int main(void) {
short arr[] = {1, 2, 3, 4, 5, 6 ,7, 8};
Filter(arr, 2, 4);
printf("---\n");
Filter(arr, 4, 2);
return 0;
}
See it running here: https://ideone.com/58KhYj

Use Initialization List in C after declaration

I am learning C and some things confuse me and the books I have read didn't really help in clarifying the problem I have.
So here is the code I have:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 5
// gcc -std=c99 stackoverflow-example.c
int main () {
// declare variable array1
int array1[ARRAY_SIZE];
// declare and init variable array2
int array2[ARRAY_SIZE] = {}; // for integers, the default value is 0
// not initialized
for (int i = 0; i < ARRAY_SIZE; i++) {
// can be anything, not guaranteed to be 0
printf("array1[%d]: %d\n", i, array1[i]);
}
// initialized with initialization list
for (int i = 0; i < ARRAY_SIZE; i++) {
// element == 0
printf("array2[%d]: %d\n", i, array2[i]);
}
// This is the part that confuses me.
// array1 = {}; // error: expected expression before ‘{’ token
// array1[] = {}; // same error
return EXIT_SUCCESS;
}
Is there a handy way to initialize this array after its declaration? Or the only way to set every element in array1 is with a for loop, e.g.:
for (int i = 0; i < ARRAY_SIZE; i++)
array1[i] = 0;
// initialized with a for loop
for (int i = 0; i < ARRAY_SIZE; i++)
// now it's guaranteed to be 0
printf("array1[%d]: %d\n", i, array1[i]);
I really appreciate your help. I know it's somewhat of a noob question, but it came up as I was trying to get more comfortable with the C language and tried some non-book-example code.
If you suspect, that there might be something fundamental that I didn't get, please let me know, I'll read up on it.
Technically speaking, initialization can be done once and only at declaration time, any value storing after that is assignment or copying.
A brace-enclosed initializer list can be used for initialization of arrays only at the declaration time.
For an individual element of an array, (a scalar item), the rule is: (quoting C11, chapter §6.7.9)
The initializer for a scalar shall be a single expression, optionally enclosed in braces.
and an empty list {} is not a valid initializer (expression) for a scalar. hence you got the error.
So, for an already defined array, the re-setting has to be done either
member-by-member, via a loop
using memcpy(), or memset if so permits.

Passing an Array to a structure in C

In order to fill a structure with integers (to then be passed on further in the program) I thought the following would work:
main() {
struct songs {int pitch[5], length[5];} songs[4];
int i[5]={1,22,23,14,52};
int k=0;
songs[0].pitch=i;
for (k=0; k<5; k++) printf("%d\n",songs[0].pitch[k]);
}
however this comes up with an error "incompatible types in assignment"
if I dont however pass this array to the structure, using the following:
main() {
int i[5]={1,22,23,14,52};
int k=0;
for (k=0; k<5; k++) printf("%d\n",i[k]);
}
it compiles and will display the content of the array.
I realise there is probably a simple fix to this, but any help would be brilliant!
Thanks in advance
C89 does not allow you to assign an array to another array. Here's the relevant bit from C99, but the text is much the same in C89 with the exception of the mention of the C99 only type _Bool. (I only have paper copies of C89)
Arrays don't fit any of these conditions -- they aren't arithmetic types, they aren't of structure or union type, and they're not pointers1. Therefore you can't use the assignment operator on them.
You can, however, use memcpy. If you replace this line:
songs[0].pitch=i;
with this line:
memcpy(songs[0].pitch, i, sizeof(i));
you'll get the behavior you expect. (After including <string.h> first of course)
1 Technically speaking 6.3.2.1/3 says that the array is converted into an rvalue pointer before it is seen by operator=, but such an assignment is still prohibited because 6.5.16/2 requires that the left side of an assignment be an lvalue.
Due to the way C handles arrays you can't assign to one like that. You need to copy over the values, either individually or via memcpy (or similar functions). Example:
for (k=0; k<5; k++){
songs[0].i[k] = i[k];
}
or:
memcpy(songs[0].i, i, sizeof i);
Note that memcpy requires you to include <string.h>
You will need to copy the array elements individually. Also the main function really should return an int.
int main( void ) {
struct songs {int pitch[5], length[5];} songs[4];
int i[5]={1,22,23,14,52};
int qq, k=0;
for( qq=0; qq<5; qq++) {
songs[0].pitch[qq]=i[qq];
}
for (k=0; k<5; k++) printf("%d\n",songs[0].pitch[k]);
return 0;
}
C does not let you copy arrays into arrays. You have to do an element by element copy.
struct songs {int pitch[5], length[5];} songs[4];
int i[5]={1,22,23,14,52};
int k=0;
for (k=0; k<5; k++) songs[0].pitch[k] = i[k];
for (k=0; k<5; k++) printf("%d\n",songs[0].pitch[k]);
when you declare an array, you have 2 options:
int * i; // #1; you do this when you don`t know the size
int i[size]; // #2
you can not assign an array to another array.
what you need to do, as others suggested, is to copy all elements of the array one by one:
for (int j = 0; j < 5; j++) {
songs[0].pitch[j] = i[j];
}
remember that using the index operator, [], is the same as dereferencing the pointer.
even more, when you say pitch[j] you actually move the pointer j positions forward and dereference it; like you would be saying *(pitch+j)
the following, compiles, runs, works.
notice the correction to the declaration of main
notice the addition of #include string.h to support memcpy function
notice the proper return statement at the end
and most importantly,
notice the correct method of copying an array
as a side note:
making the struct tag name and the instance name the same
is very bad programming practice
#include <stdio.h>
#include <string.h>
int main()
{
struct songs
{
int pitch[5];
int length[5];
} songs[4];
int i[5]={1,22,23,14,52};
int k=0;
memcpy( songs[0].pitch, i, sizeof( i ) );
for (k=0; k<5; k++)
{
printf("%d\n",songs[0].pitch[k]);
} // end for
return(0);
}
Problem is here,
songs[0].pitch=i;
Use int* in the structure, You can't assign an array to another array and name of the structure and the structure object.
This would work.
struct Songs {int* pitch, length[5];} songs[4];

what is "error: variable-sized object may not be initialized"?

I'm trying to fill an array with numbers from 1-100 with this code:
#include <stdio.h>
int main()
{
int num[100];
int i = 0;
for (i = 0; i < 100; i++)
{
int num[i] = i+1;
}
}
but I'm getting this error:
c:18:13: error: variable-sized object may not be initialized
I'm still relatively new to programming so I'm not sure what this means. Can you tell me?
Replace this
int num[i] = i+1;
For this:
num[i] = i+1;
You already declare the array on the top int num[100];
First you declare the array, and then you iterate over it inside the loop.
Since you are new, it is preferable you start by reading a good book about the subject my recommendation.
The problem is the int in int num[i] = i+1. The compiler thinks you're trying to declare a new array (also called num) with i elements in it (that's the variable-sized object part). Just remove the int from that line.
You are declaring the array again in the loop:
int num[i] = i+1;
Anyway, this is the error in your code but the problem for the compiler is not there: it gives you that error because that's not a valid declaration with initialization for an array. If you just write int num[i]; the code it's valid code and it will compile without error (well, only from C99, old C89 doesn't support variable-length arrays). This is what the compiler recognizes and tries to report.

Resources