Can we initiate an array literal with variables in C? - arrays

I have been searching if we can initiate an array literal with variables but couldn't find it. Bit of context, I want to pass an array literal to a function. Below is what I am trying to do:
int fun(int * a, int num){
int sum=0;
for (int i=0; i< num; ++i){
sum = sum + a[i];
}
return sum;
}
int main(){
int a = 3, b =2, c = 1 ;
int x[3] = {a,b,c}; // Is this legal? It compiles fine on all compilers I tested.
int p = fun( (int[3]){a,b,c} , 3); // I want to do something like this. pass a literal to the fucntion
return 0;
}

From the C Standard (6.7.9 Initialization)
4 All the expressions in an initializer for an object that has static
or thread storage duration shall be constant expressions or string
literals.
The string literal defined in this record
int p = fun( (int[3]){a,b,c} , 3);
has automatic storage duration. So you may initialize it with non-constant expressions in particularly using the variables a, b, and c.
Pay attention to that as the function does not change the passed array then the first parameter should have the qualifier const and to avoid overflow it is better to declare the return type as long long int.
Here is a demonstration program.
#include <stdio.h>
long long int fun( const int * a, size_t n )
{
long long int sum = 0;
for ( size_t i = 0; i < n; ++i )
{
sum += a[i];
}
return sum;
}
int main( void )
{
int a = 3, b = 2, c = 1 ;
printf( "%lld\n", fun( ( int[] ){a, b, c} , 3 ) );
}

Your code (sans the extra x array) compiles just fine with -std=c99 so yes, I'd say it's standard C99 code.
#include <stdio.h>
int fun(int a[], int num) {
int sum = 0;
for (int i = 0; i < num; ++i) {
sum = sum + a[i];
}
return sum;
}
int main() {
int a = 3, b = 2, c = 1;
int p = fun((int[3]){a, b, c}, 3);
printf("%d", p);
return 0;
}

This would not be allowed if the initializer is static, since the value needs to be assigned before the program executes. From C99:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
Otherwise, each initializer needs to be an "assignment-expression" or, in other words, a valid expression that can be assigned to an object.
So yes, this is legal in C.

Well, yes. The array is being initialized as it should which can be tested by printing it.
The array is also being sent to the function properly as p returns 6. However, do note that you are making a new array to send to the function.

Related

How to assign Pointer to an Array, to a new Array?

I got this code:
#include <stdio.h>
#include <string.h>
int main(void)
{
int a[3]={1,2,3},
b[3];
int (*p)[3]= &a;
b = p;
for(int i=0;i<3;i++)
printf("%i",b[i]);
}
-I wanted output to be like "123", but I am having problems assigning the b array to what the p is pointing.
ps -
memcpy( b, p, sizeof(b)); does just what i want but i want to do it without the use of that function.
The line
b = p;
has a couple of problems. First of all, array expressions may not be the target of the = operator; you can't assign an entire array in a single operation like that1.
Secondly, the types don't match; p has type int (*)[3], while b has type int [3]. Arrays are not pointers - array expressions "decay" to pointer expressions under most circumstances, but in this case even the pointers would be of incompatible types (b would decay to an expression of type int *, not int (*)[3]).
No, the only ways to copy the contents of one array to the other are to use library functions like memcpy or to use a loop to assign each element individually:
for ( size_t i = 0; i < 3; i++ )
b[i] = (*p)[i]; // or b[i] = a[i]
That's it.
Initialization is different from assignment.
Arrays do not have the assignment operator. You need somehow to copy elements of one array to another array.
Without using the standard function memcpy you can use an ordinary loop as for example
for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
{
b[i] = a[i];
}
Or if to use intermediate pointers you can write
for ( int *p = a, *q = b; p != a + sizeof( a ) / sizeof( *a ); ++p )
{
*q++ = *p;
}
You have a small fixed size array, perfectly suitable for wrapping inside a struct, so you can do this:
#include <stdio.h>
#include <string.h>
struct ia3 {
int data[3];
}
int main(void)
{
struct ia3 a = {{1,2,3}};
struct ia3 b;
struct ia3 *p = &a;
b = *p; // struct assignment
for(int i=0;i<3;i++) {
printf("%i",b.data[i]);
}
}
"...but i want to do it without the use of [memcpy(,,)]."
It is unclear why using memcpy() is not agreeable in this exercise, but it does do the task more efficiently then loop for large array sizes.
If you just want a pointer to the array...
int a[3] = {1,2,3};
//create pointer
int *b = a;//does not copy array a, just points to it
//If an additional array is needed, do this...
int b[3] = {0};
int i = 0;
//to copy, without memcpy(), use this alternative.
for(i=0; i<3; i++) b[i] = a[i];//makes copy of array a
for(i=0;i<3;i++)
printf("%i", b[i]);

What does something like int *array[99] = {0}, *u do?

bool checkSubarraySum(int* nums, int numsSize, int k) {
int i, s, found = 0;
e_t buff[10000];
int n;
e_t *set[SZ] = { 0 }, *e;
put(set, &buff[n ++], 0, -1);
s = 0;
for (i = 0; i < numsSize; i ++) {
s += nums[i];
if (k) s = s % k;
e = lookup(set, s);
if (e) {
if (i - e->idx >= 2) {
found = 1;
break;
}
} else {
put(set, &buff[n ++], s, i);
}
}
return found;
}
What is e_t *set[SZ] = { 0 }, *e; doing? e_t is a user defined type but I don't think that matters. e is not a pointer that has been defined anywhere in global scope to my knowledge, and I tried something like the following:
int *array[5] = {0}, *u;
and no syntax errors were given. The first part, i.e. int *array[5] = {0} initializes all five elements of this array to 0. But what is the purpose of *u? You can't just assign an array to something else, right, it's an address, not a pointer. And u has never even been defined, so, I would expect some sort of NameError...
Thanks for any help in advance.
It is similar to typing:
int x, y;
but notice the types when typing something like:
int a, *b, **c;
/* ^ ^ ^
* int int* int**
*/
therefore
int *array[5] = {0}, *u;
/* ^ is pointer to int */
int *array[5] = {0}, *u;
Is a declaration of two int objects. The first:
int *array[5] = {0}
declares an array-of-pointers to int [5] (meaning an array of 5 pointers to int) initialized to NULL by virtue of using the "universal initializer" {0}. The equivalent, but more intuitive initialization would be:
int *array[5] = {NULL}
The ',' is simply a separator here that allows the second declaration *u to be included in the same line without a separate int *u; declaration.
(not to be confused with the comma-operator that simply discards expressions to the left of the final ',' evaluating the last expression. See What does the comma operator , do? -- thank you #AnttiHaapala)
So:
..., *u;
declares a single (uninitialized) pointer-to int.
e_t *set[SZ] = { 0 }, *e;
is a declaration of two objects; set is an array of pointers to e_t, while e is a pointer to a single e_t. It may also be written as:
e_t *set[SZ] = {0};
e_t *e;
e_t *set[SZ] = { 0 }, *e; should be read as "the programmer hereby declares that the following are of type e_t: the objects pointed to by each SZ elements in set; and the object pointed to by e."
= {0} causes each element in set to be initialized to null pointers - the first explicitly and the remaining implicitly.

passing address in c

In the following code example:
typedef struct data{
char ch;
int n;
int n2;
}DATA;
void Func3(DATA d){
int sum;
sum = d.ch + d.n;
d.ch = 'c';
d.n = 0x77;
}
void Func4(DATA &d){
int sum;
sum = d.ch + d.n;
d.ch = 'k';
//d.n = 0x88;
}
int WINAPI WinMain(HINSTANCE hlnst, HINSTANCE hprev,
LPSTR lpCmd, int nShow)
{
DATA dt;
dt.ch = 'a';
dt.n = 10;
dt.n2 = 20;
Func3(dt);
Func4(dt);
return 0;
}
Are Func3() and Func4() the same thing?
Are both functions pass-by-reference?
Is there any difference between the two functions?
You are compiling this with a C++ compiler. DATA &d is not syntactically correct in C.
In Func, the compiler essentially writes DATA d = dt before the function body is entered.
In Func2 that "assignment" does not happen. The C++ compiler sets d to be a reference to dt. So changes to d in Func2 are reflected in the caller as changes to dt.
In your specific case though, an optimising compiler will recognise that both functions are no-ops, and so will probably compile them out.
In C there is no reference '&' type variables like in C++.
You have to pass the address to get the same affect. FUNC2() in C with 'd' as pass by reference will look like below:
void Func2(DATA *d){
int sum;
sum = d->ch + d->n;
}
When in C there is used words "pass by reference" then it means that an object is passed to a function indirectly by means of a pointer to the object.
Consider the following demonstrative program
#include <stdio.h>
void f( int *sum, int x, int y )
{
*sum = x + y;
}
void g( int sum, int x, int y )
{
sum = x + y;
}
int main( void )
{
int x = 1, y = 2;
int sum;
sum = 0;
printf( "Before call of f sum = %d\n", sum );
f( &sum, x, y );
printf( "After call of f sum = %d\n", sum );
sum = 0;
printf( "Before call of g sum = %d\n", sum );
g( sum, x, y );
printf( "After call of g sum = %d\n", sum );
}
The program output is
Before call of f sum = 0
After call of f sum = 3
Before call of g sum = 0
After call of g sum = 0
The first function, function f. accepts the argument sum by reference that is using a pointer to sum. Thus after the function call the variable sum was changed.
The second function, function g, accepts the argument sum by value that is the function deals with a copy of the argument. Thus any changes of the copy do not influence on the value of the original argument.
In C++ apart from this meaning of the words "pass by reference" in the frames of C there is additional meaning because C++ introduced the notion of references like special kind of declarators and correspondingly defined the notion of the reference type.
Thus in C++ you can one more possibility to pass a value by reference. You may use a reference type. For example you could define a function for the example above the following way
void f( int &sum, int x, int y )
{
sum = x + y;
}
In this case as the argument is passed by reference that is the corresponding parameter type is a reference type then the function will deal with the original argument instead of its copy.
.

Passing multidimensional array in another way?

#include <stdio.h>
void arraypass(int from, int to, int a[][2]);
int main()
{
setbuf(stdout, NULL);
int t1 = 0, t2 = 0;
int testArray[10][2];
for (t1 = 0; t1 < 10; t1++)
{
testArray[t1][t2] = t1 + 1;
}
t2++;
for (t1 = 0; t1 < 10; t1++)
{
testArray[t1][t2] = t1 + 10;
}
arraypass(1,5,testArray);
return 0;
}
void arraypass(int from, int to, int a[][2])
{
int b;
for (b = from; b <= to; b++)
{
printf("%d ",a[b][0]);
printf("%d\n",a[b][1]);
}
}
Why is it that
int a[][2]
works, but not
int a[][]
for the argument definitions in this?
void arraypass(int from, int to, int a[][2]);
And, is there a way to possibly pass an entire multidimensional array at once, or do I need to perform some kind of loop?
For the compiler, a vector is a hidden pointer to its first item.
For example:
int a[2];
a[0]=0;
a[1]=1;
is the same of:
int a[2];
*(a+0)=0;
*(a+1)=1;
When you pass a multidimensional array (o a simple array) you should use pointers instead of a vector:
void arraypass(int from, int to, int **a);
and then if you want to use it you could do something like this:
void arraypass(int from, int to, int **a){
int i,j;
for(i=from; i<end; i++) {
for(j=0; j<2; j++) {
printf("%d",a[i][j]);
}
}
You have to remember that arrays decays to pointers. That means, when they are (for example) passed as arguments to functions the function receives a pointer.
What int a[][2] does, is the same as int (*a)[2], which means that a is a pointer to an array of two int. That is different from a pointer to an array of any other dimension, which is why you don't have to specify the primary "dimension" (as that to the compiler is the same as a pointer) but you do have to specify the other "dimension(s)".
This is related to this answer in the C FAQ.
Because the function receives a pointer when an array is passed to a function, the compiler needs to know the dimensionality of the array that the pointer will be to (in this case, two), but doesn't care how long the sequence of pointers to two-element arrays is going to be.

what's the difference between int (* f [])(); and int f[]();

i find this in Pointers on C
int f[](); /* this one is illegal */
and:
int (* f [])(); /* this one legal. */
i really want know what's the usage of the second one.
thank you.
The second example is quite valid, if you use initialization block. For example:
#include <stdio.h>
int x = 0;
int a() { return x++ + 1; }
int b() { return x++ + 2; }
int c() { return x++ + 3; }
int main()
{
int (* abc[])() = {&a, &b, &c};
int i = 0,
l = sizeof(abc)/sizeof(abc[0]);
for (; i < l; i++) {
printf("Give me a %d for %d!\n", (*abc[i])(), i);
}
return 0;
}
I'm not sure if the second example is legal, since the size of the function array is not known, but what it is supposed to be is an array of function pointers, and here is a possible example of usage if the size would be known:
int a()
{
return 0;
}
int main(int argc ,char** argv)
{
int (* f [1])();
f[0] = a;
}
int f[](); // this is illegal because of you can't create array of functions . It's illegal in C
But second is legal
int (* f [])(); It says that f is an array of function pointers returning int and taking unspecified number of arguments
int f[](); /* this one is illegal */
That's trying to declare an array of functions, which is impossible.
int (* f [])(); /* this one NOT legal, despite what the OP's post says. */
That's trying to declare an array of function pointers, which would be perfectly legal (and sensible) if the array size were specified, e.g.:
int (* f [42])(); /* this one legal. */
EDIT: The type int (* f [])() can be used as a function parameter type, because for function parameter types, array-to-pointer conversion takes place immediately, meaning we don't ever need to specify the dimension of the innermost array of a (possibly multidimensional) array:
void some_func(int (* f [])()); /* This is also legal. */

Resources