struct forces{
double fo[1];
double ft[1];
};
int main(void){
struct forces frc;
frc.fo[0]=6;
frc.fo[1]=56;
frc.ft[0]=567;
printf("%.0lf\n",frc.fo[1]);
return 0;
}
Please assist. Why is my printout always frc.ft[0]?
With your declaration, fo[1] does not exist and writing to it is undefined behavior for C and C++.
Change your declaration to this to make fo[1] a valid element
struct forces{
double fo[2];
double ft[1];
};
In C and C++ (and most similar languages) a declaration of foo[5] creates a 5-element array with valid index values of [0] ... [4]. int foo[1] only has a valid index foo[0]
With your code you see fo[1] in place of ft[0] because your compiler placed the two double variables together in memory with no gap (padding) between them.
Related
What does the code below print when running the function print_test()?
struct test {
int a, b, c;
};
void print_test(void) {
struct test t = {1};
printf("%d/%d/%d", t.a, t.b, t.c);
}
Solution 1\0\0
Why are b and c initialized to zero even though I did not do it? Are there any default values for the struct?
However, the struct is not global and the member is not static. Why are they automatically zero-initialized? And if the data type were not int another data type to which value will be initialized?
If you don't specify enough initializers for all members of a struct, you'll face Zero initialization, which will initialize remaining members to 0. I think by today's standards this seems a bit odd, especially because C++'s initialization syntax has evolved and matured a lot over the years. But this behavior remains for backwards-compatibility.
I think we need to know two points at this stage:
There is nothing different between regular variables and structs, if they are at local scope i.e automatic storage duration. They will contain garbage values. Using those values could invoke undefined behaviour.
The only thing that makes structs different is that if you initialise at least one of the members, the rest of the members will get set to zero i.e. initialised as if they had static storage duration. But that's not the case when none of the members are initialised.
It depends on your declaration.
If your declaration is outside any function or with the static keyword (more precisely, has static storage duration), the initial value of x is a null pointer (which may be written either as 0 or as NULL).
If it's inside a function i.e. it has automatic storage duration, its initial value is random (garbage).
consider the following code:
#include<stdio.h>
#include<unistd.h>
struct point {
int x, y;
char a;
double d;
};
typedef struct point Point;
void main(){
Point p1;
printf("\nP1.x: %d\n", p1.x);
printf("\nP1.y: %d\n", p1.y);
printf("\nP1.a: %d\n", p1.a);
printf("\nP1.d: %lf\n", p1.d);
Point p2 = {1};
printf("\nP2.x: %d\n", p2.x);
printf("\nP2.y: %d\n", p2.y);
printf("\nP2.a: %d\n", p2.a);
printf("\nP2.d: %lf\n", p2.d);
}
The output is :
P1.x: 0
P1.y: 66900
P1.a: 140
P1.d: 0.000000
P2.x: 1
P2.y: 0
P2.a: 0
P2.d: 0.000000
A Good read: C and C++ : Partial initialization of automatic structure
I often use :
Array wrappers to pass array by value but the problem is that the size of array is determined at compile time (see part I of the code)Array declarations that depend of a variable (see part II of the code)
How is it possible to "combine" these two types of code to have array wrappers that depends of a variable ? (see part III of the code. I know it can not work because there is a variable in structure declaration, it is just here to give an idea)
#include <stdio.h>
int main() {
// First part of code
// Array wrapper to pass array by value but size of array is determined at compile time
struct S {int m_array[5];} myarray={1,2,3,4,5};
struct S myarraycopy;
struct S copyarray(struct S a) { return a ;}
myarraycopy=copyarray(myarray);
for (int i=0;i<5;i++) printf("%d \n",myarraycopy.m_array[i]);
// Second part of code
// Array declaration is function of a variable n and
// so it is not determined at compile time
int n;
printf("Size : ");scanf("%d",&n);
int myarray1[n];
for (int i=0;i<n;i++) myarray1[i]=i;
printf("Array size %d \n",sizeof(myarray1));
for (int i=0;i<n;i++) printf("%d \n",myarray1[i]);
/* How to combine the two parts above ???
int n1;
printf("Size : ");scanf("%d",&n1);
struct S1 {int m_array[n1];} myarray1;
struct S1 myarraycopy1;
struct S1 copyarray1(struct S1 a) { return a ;}
myarraycopy1=copyarray1(myarray1);*/
}
How is it possible to "combine" these two types of code to have array wrappers that depends of a variable ?
You cannot, at least in standard C. In the standard's terms, the members of a structure type cannot be variably-modified. This serves the purpose that the size of a structure type is always a compile-time constant (even, technically, structure types having flexible array members).
In the general case, you have the alternative of passing your array normally, in the form of a pointer to its first element. You may declare the function parameter as a pointer to const elements, so that the function cannot modify the array (at least, not without casting away the constness, which you could surely persuade your compiler to warn about).
That does not serve your copyarray() use case, because you cannot return arrays (as such) either, nor assign to whole arrays. But memcpy() does that job fine without need for wrapping or passing around arrays by value, so the case seems contrived.
I try to use flexible array member (see code below). I am not surprised that this code does not work. Indeed, the size of the flexible array is not know at compile time (cf standard 6.7.2.1 *s1=*s2;). But, as the size of myarray1 is known ( sizeof(S1)+n1*sizeof(int) ), I wonder if Inline Assembly Language in the code could be used to force the copy of the whole variable myarray1.
#include <stdio.h>
typedef struct {int l;int m_array[];}S1;
void myfoo(S1 a) {
for (int i=0;i<a.l;i++) a.m_array[i]*=10;
printf("in myfoo\n");
for (int i=0;i<a.l;i++) printf("%d \n",a.m_array[i]);
}
int main() {
int n1;
printf("Size : ");scanf("%d",&n1);
S1 *myarray1=malloc(sizeof(S1)+n1*sizeof(int));
myarray1->l=n1;
for (int i=0;i<n1;i++) myarray1->m_array[i]=i;
myfoo(*myarray1);
printf("in main\n");
for (int i=0;i<n1;i++) printf("%d \n",myarray1->m_array[i]);
}
I recently started writing chunks of C code as part of my university's programming lessons (so you can freely assume that I am a complete idiot). I'm trying to write a function that writes a 2D array's data to a file, but I'm having difficulties. I declare the array in main, I have its x and y dimensions saved as #defines, and I want to call my function() like so;
include "function.h"
#define /* x_res, y_res */
int main(){
static unsigned char pic[x_res][y_res];
/* do some operations on pic*/
function(pic,x_res,y_res);
}
The function itself is saved in a header file and is intended to be included at the very top of my main .c file. It goes something like this;
void function(unsigned char arry,int x_res,int y_res){
/* some calculations, declaring file pointer with fopen() */
for(int i=0;i<y_res;i++){
for(int j=0;j<x_res;j++){
fprintf(f,"%c",arry[i][j]);
}
}
}
I'm greeted with an error in the line fprintf(f,"%c",arry[i][j]); saying that the "subscripted value is neither array nor pointer nor vector", which is false since I know that arry is an array. Furthermore, if I try to replace said line with something like fprintf(f,"%c",arry[i*j+j]);, the error goes away, but the file output is gibberish (I'm assuming I'm only printing the addresses of the first-dimension elements of arry).
The question, then; Why can't 2D arrays be accessed like their 1D counterparts, and how do I work around this? I would imagine that an int array[][]={{0,1},{2,3}}; would give an output of
array[0] -> 0
array[1] -> 1
array[2] -> 2
array[3] -> 3
, but this is not the case -- it prints 0, 2, and then two memory addresses.
I've tried declaring my function to accept arguments as void function(unsigned char arry[*value of x_res*][*value of y_res*],x_res,y_res), which works but is not how I would like the function to work.
I've looked at some other online examples but it seems few people have had a similar problem. I tried some answers from this question but again things do not work. For example, using void function(unsigned char **arry,x_res,y_res) works with accessing the array as 2D (arry[i][j]), but again, like with the example above, most values (all that aren't in the first column) are trash.
In C99 and later, it is possible to have a VLA
void function(int x_res, int y_res, int char[][y_res])
{
for(int i=0;i<x_res;i++)
{
for(int j=0;j<y_res;j++)
{
fprintf(f,"%c",arry[i][j]);
}
}
}
The problem is that support of an implementation for VLAs was made optional in C11 (i.e. a C11 compiler is not required to support them). And VLAs are definitely not supported in C90 (the ISO C standard of 1990).
An declared array is contiguous in memory, so can be treated like a flat 1D array. For example;
void function2(int x_res, int y_res, unsigned char *arr)
{
for(int i=0;i<x_res;i++)
{
for(int j=0;j<y_res;j++)
{
fprintf(f,"%c",arr[i*y_res + j]);
}
}
}
int main()
{
unsigned char x[10][20];
unsigned char y[10*20];
unsigned char *z = malloc(10*20*sizeof(*z));
/* initialise elements x, y, and z */
function2(10,20, (unsigned char *)x);
function2(10,20, &x[0][0]);
function2(10,20, y);
function2(10,20, z);
}
The type conversion in the first call of function() is needed since a 2D array of unsigned char cannot be implicitly converted to a unsigned char *. However, the address of x and the address of x[0][0] have the same value, even though they have different types.
A gotcha with this technique is that the dimensions passed (first two arguments of function2()) are not checked at compile time. For example;
int xx[5][6];
function2(10, 20, (unsigned char *)xx); /* danger, Will Robinson!! */
function2(10, 20, &xx[0][0]); /* danger, danger!! */
will compile but, since the dimensions of xx are less than the first two arguments tell function2() to expect, will cause function2() to have undefined behaviour for both calls.
I have an API which will take triple pointer as an input as below.
extern int myAPI(int ***myData);
Internally "myData" is treated as array of pointer to array of pointers.
So now in another function, i need to call this myAPI. But i am not able to build the array of pointer to array of pointers. Can you please someone help?
I tried similar to below snippet of code. But seen type mismatch compilation error.
int i[10];
int j[10];
int *k[10];
int *l[10];
int *(*m[])[2];
int a = 0;
for (a = 0; a < 10; a++) {
k[a] = &(i[a]);
l[a] = &(j[a]);
}
m[0] = k;
m[1] = l;
a = myAPI(m);
So you want an "array 10 of pointer to array of pointer 20 to int" (you have to specify the dimensions for all but functions arguments where you can omit the outermost dimension only).
That would be:
int *(*a[10])[20];
For such constructs, cdecl is very helpful. The line in quotes is the declaration for the tool.
Note this is what you asked for. Which is not necessarily what you really need. Often such complex constructs are a symptom of a severe design flaw. You might want to reconsider your program code.
Try changing the declaration of m to
int **m[2];
Let's say that any C function has a pointer already declared, but not assigned any value yet. We will int for our examples.
int *ptr;
The goal of the function is not to assign ptr any dynamic memory on the heap, so no malloc call. Instead, we want to have it point to an array of fixed size n. I know I could accomplish this like so:
int arr[n];
ptr = arr;
However, the code could get very messy and hard to read if we need to do this many times in a function, ie, a struct of many pointer fields all need to point to an array of fixed length. Is there a better way to accomplish this in one line? I was thinking of something similar to below, but it looks too ambiguous and uncompilable:
int *ptr;
// Many other things happen in between...
ptr[n];
***EDIT***
Here, the below additional information may help guide some more answers (not saying that the current answers are not fine). In my use case, the pointers are declared in a struct and, in a function, I am assigning the pointers to an array. I want to know if there is a simpler way to accomplish this than in the below code (all pointers to point to fixed-length array):
struct foo {
int* a;
short* b;
char* c;
...
};
void func(void) {
struct foo f;
int n = ...;
int tempArr1[n];
f.a = tempArr1;
short tempArr2[n];
f.b = tempArr2;
char tempArr3[n];
f.c = tempArr3;
...
}
You cannot declare an array and assign it to an existing pointer in a single declaration. However, you can assign an array pointer to a newly declared pointer, like this:
int arr[n], *ptr = arr;
If you insist on staying within a single line, you could use an ugly macro, like this:
#define DECL_ASSIGN_INT_ARRAY(name,size,pointer) int name[(size)]; pointer = name;
The clarity of this one-liner is far lower than that of a two-line version from your post, so I would keep your initial version.
EDIT (in response to the edit of the question)
Another option is to create an unused pointer variable in a declaration, and assign your pointer in an initializer, like this:
void func(void) {
struct foo f;
int n = ...;
int tempArr1[n], *tempPtr1 = f.a = tempArr1;
short tempArr2[n], *tempPtr2 = f.b = tempArr2;
char tempArr3[n], *tempPtr3 = f.c = tempArr3;
...
}
This seems like a clear case where you're in need of some refactoring. Take the similar statements, extract them into a new function (by passing a reference to the struct and the data you want the struct fields to point to) and give this new function a meaningful name.
This is probably more maintainable and readable than some fancy pointer arithmetic shortcut that you'll forget about in a few weeks or months.
The difference between ptr and arr in you example is you can change ptr's value. So I guess you want to move ptr through the array.
So how about this:
int arr[n], id=0;
And you change the value of id and use arr+id as ptr.
I guess the way to do this is to use a macro. Something like (untested)
#define autoptr(name,size) int Arrayname[size]; name = Arrayname;
I'm not clear why this is helping I think it might "look ugly" but will be easier to maintain without the macro. In general, hiding what you are actually doing is a bad thing.