Here is my code:
int dim_y, dim_x;
int **map_boundaries;
int **map;
int main( int argc, char* args[] ){
int i;
scanf("%d",&dim_x);
scanf("%d",&dim_y);
map_boundaries = (int **)calloc(dim_y + 40,sizeof(int*));
for(i = 0; i < dim_y + 40; i++){
map_boundaries[i] = (int *)calloc(dim_x + 40,sizeof(int));
}
(*map)[dim_x+40] = (int(*)[dim_x+40])&map_boundaries[20][20];
}
The warning is for the last line, how should the last line be?
When I have it like this it works fine:
#define dim_y 500
#define dim_x 600
int map_boundaries[dim_y+40][dim_x+40];
int (*map)[dim_x+40] = (int(*)[dim_x+40])&map_boundaries[20][20];
But I want the values of "dim_x" and "dim_y" to be provided by the user and "map" to be global.
First, we need to know what do you want to achieve. There is something obviously wrong with the last line, but without knowing your intent we will only guess how to fix it. Let's analyze your code.
Currently you are dereferencing (uninitialized) (int**) variable ((int*)) and then using it like array - this suggest that you intend map to be pointer to array of ints.
You are dynamically allocate 2-dimensional map_boundaries array with size of (dim_x+40) x (dim_y+40) - note that valid indexes will be respectively 0...dim_x+40-1 and 0...dim_y+40-1.
From your edit I understand that you want to use map_boundaries as helper to dynamically allocate global map.
Indeed you can allocate table like like you did. To assign whole array of map_boundaries to map you only need to do map = map_boundaries; like #BLUEPIXY suggested. Then You can make map_boundaries local.
int dim_y, dim_x;
int **map;
int main( int argc, char* args[] ){
int **map_boundaries;
scanf("%d",&dim_x);
scanf("%d",&dim_y);
map_boundaries = (int**) calloc(dim_y+40, sizeof(int*));
for(int i = 0; i < dim_y+40; i++){
map_boundaries[i] = (int*) calloc(dim_x+40, sizeof(int));
}
map = map_boundaries;
}
Warning occurs because:
(*map)[dim_x+40] is type of int (and you obtain it by dereferencing unallocated memory but compiler cannot know that).
(int(*)[dim_x+40]) is (if I'm not mistaken) of type array of pointers to int ((int*)[]) - compiler implicitly cast it to int since you jest cast data into invalid type.
If that's not what you wanted to do, please elaborate on what you actually were trying to achieve, since it is not obvious.
EDIT:
Trimming map_boundaries to map (one way to do it):
int trimmed_dim_y_start = 0;
int trimmed_dim_y_size = 20;
int trimmed_dim_x_start = 0;
int trimmed_dim_x_size = 20;
// ...
map = (int**) calloc(trimmed_dim_y_size, sizeof(int*));
for (int i = 0; i < trimmed_dim_y_size; i++) {
map[i] = map_boundaries[ trimmed_dim_y_start + i ] + trimmed_dim_x_start;
}
Note that in this variant you'll have to make map_boundaries global again since if you don't free all that calloc's you'll get memory leak. Maybe not so bad in this particular program but it's still an important practice to clean up things.
Remove bracket from int(*) and place all int* in brackets.
(*map)[dim_x+40] = ((int*)[dim_x+40])&map_boundaries[20][20];
Related
Suppose we want to construct an array of structs, where the definition of the struct cannot be known at compile time.
Here is a SSCCE:
#include <stdlib.h>
int main(int argc, char *argv[]){
if (argc < 3) return 1;
int n = atoi(argv[1]);
int k = atoi(argv[2]);
if ((n < 1) || (k < 1)) return 2;
// define struct dynamically
typedef struct{
int a[n];
short b[k];
}data_point_t;
int m = 10;
// construct array of `m` elements
data_point_t *p = malloc(sizeof(data_point_t)*m);
// do something with the array
for(int i = 0; i < m; ++i) p[i].a[0] = p[i].b[0] = i;
free(p);
return 0;
}
This works fine with gcc (C99), however it doesn't with clang, which yields:
error: fields must have a constant size:
'variable length array in structure' extension will never be supported
So I'm obviously relying on a gcc extension. My question is, how to deal with this kind of problem in standard conform C99? (Bonus question: how to do this in C++11?)
Note: Performance matters, when iterating p there should be aligned memory access. Dereferencing pointers in the loop, yielding random memory access, is not an option.
I think your best bet is to drop the idea of wrapping the array in a structure, bite the bullet and allocate a 2D array yourself.
This will mean that you need to do explicit indexing, but that would have to happen under the hood anyway.
When it comes to alignment, if you're going to visit every n array elements in each of the m arrays, it probably doesn't matter, it's better to make them compact to maximize use of cache.
Something like:
int *array = malloc(m * n * sizeof *array);
Then to index, just do:
// do something with the array
for(int i = 0; i < m; ++i)
{
for(int j = 0; j < n; ++j)
array[i * n + j] = j;
}
If you're very worried about that multiplication, use a temporary pointer. After profiling it, of course.
Sometimes you see this done with a helper macro to do the indexing:
#define INDEX(a, n, i, j) (a)[(i) * (n) + (j)]
then you can write the final line as:
INDEX(array, n, i, j) = j;
it's a bit clumsy since the n needs to go in there all the time, of course.
First of all, it only makes sense to wrap the array inside a struct in the case there are other struct members present. If there are no other struct members, simply allocate an array.
If there are other struct members, then use a flexible array member to achieve what you want. Flexible array members are well-defined in the C standard and will work on every C99 compiler.
// define struct dynamically
typedef struct{
type_t the_reason_you_need_this_to_be_a_struct_and_not_an_array;
int a[]; // flexible array member
}data_point_t;
// construct array of `m` elements
int m = 10;
size_t obj_size = sizeof(data_point_t) + n*sizeof(int);
data_point_t *p = malloc(m * obj_size);
In C++ you can of course use pointers much like you do now, but for a "proper" C++ solution the only viable solution is to use std::vector:
struct data_point_t
{
explicit data_point_t(const size_t sz)
: a(sz) // Construct the vector `a` with `sz` entries,
// each element will be zero initialized (`int()`)
{}
std::vector<int> a;
};
int main(int argc, char *argv[]){
// Read `n`...
int n = 10; // Just example
// Read `m`...
int m = 10; // Just example
// Construct vector of `m` elements
std::vector<data_point_t> p(m, data_point_t(n));
// Here the vector `p` contains `m` elements, where each instance
// have been initialized with a vector `a` with `n` elements
// All fully allocated and initialized
// Do something with the array
// ...
}
This is valid C++03 code, so unless you use something ancient (like Turbo C++) any compiler today should support it.
Let's say I have a 9-dimensional array:
int arr[4][4][4][4][4][4][4][4][4];
I want to initialize every element to be 1.
I know I can initialize it using multiple loops:
for(int i1 = 0; i1 < 4; i ++) {
...// eight more similiar loops
}
But it seems ugly.
What is the best practice to do that? Maybe I can use macro?
In C, multidimensional arrays are contiguous, so you can take advantage of this by initializing arr through a pointer.
int* parr = (int*)arr;
for (int i = 0; i < ((sizeof(arr)/sizeof(int)); ++i)
parr[i] = 1;
Note that this won't work in situations where the array decomposes to a pointer (for example, if it was passed to a function as an argument).
write like this:
int *p = &arr[0][0][0][0][0][0][0][0][0];
for( int i = 0; i < 4*4*4*4*4*4*4*4*4; i++)
*p++ = 1;
#nuk because arr is a type
int[4][4][4][4][4][4][4][4][4] // 9 of '[4]'
so
int arr[4][4][4][4][4][4][4][4][4];
sizeof(arr) = sizeof(int[4][4][4][4][4][4][4][4][4]);
= sizeof(int) *4*4*4*4*4*4*4*4*4;
but if you pass a pointer here,
int* arr;
sizeof(arr) = sizeof(int*)
= sizeof(void*)
= Usually the target file's BIT / 8
Maybe use a recursive function which is passed the number levels it needs to initialize.
void init(int * arr, int level, int size, int value)
{
for(int i = 0; i < size; i++)
{
if(level == 0)
arr[i] = value;
else
init(arr[i], level - 1, size, value);
}
}
If you had wanted to initialize to zero, a good old memset would have done it:
int arr[4][4][4][4][4][4][4][4][4];
memset(&arr, 0, sizeof(arr));
That said, however, and since you want to initialize to 1 anyway, I should say that it generally seems like an at least kinda poor idea to use 9D arrays in C. You'll always have to declare that draconian type anywhere you pass it to a function, and you'll never be able to use indirect indexing in any generic way. You're probably better off just declaring a 218 large int-array and calculate the index manually, instead. It's your context, of course, so it's not as if you couldn't have your reasons. :)
Can someone please tell me what's wrong with the following code? I'm getting EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS
I declare a global array of 7 pointers, each points to an int array, of different sizes.
int **pt_all_arrays[7];
In my function A()
for (int i = 0; i < 7; ++i) {
int array_size = function_that_returns_array_size();
int *myarray = (int *)malloc(array_size * sizeof (int));
// DO WORK...
// Store the array in the big array
*(pt_all_arrays[i]) = myarray; <-----EXCEPTION
}
The exception is thrown on the last line.
I'm running on Mac, gcc -std=gnu99
You would want to declare as
int *pt_all_arrays[7];
And then assign as
pt_all_arrays[i] = myarray;
With int **pt_all_arrays[7]; you create array of pointer to pointer to int, which is not what you want.
And with *(pt_all_arrays[i]) = myarray; you are trying to change to address of array which is not valid.
Example
int array[7];
int *pi;
array = pi; //this is not valid.
the definition of
int **pt_all_arrays[7];
should be
int *pt_all_arrays[7];
In the last line , you try to write to the memory location pointed by pt_all_arrays[i]. Since pt_all_arrays[i] hasn't been initialized, this might point anywhere. In your case, it points to an invalid memory address.
int **pt_all_arrays[7];
This actaully declaires an array of 7 pointers to pointers to ints. (pointers to int arrays). So if you want to store arrays you just need:
int *pt_all_arrays[7];
When you access the array:
pt_all_arrays[i]
This is actually saying the same as:
*(pt_all_arrays + i)
So you don't want to add the additional * in to it, simply:
pt_all_arrays[i] = myarray;
Will do.
I have some inherited code and a function which takes a character array as a parameter.
typedef char myString[256];
void MyFunc(myString param)
{
int i;
for (i = 0; i < 256; i++)
{
if (param[i] ....
I would like to make this more efficient and pass a pointer to the char array:
void MyFunc(myString *param)
{
int i;
for (i = 0; i < 256; i++)
{
if (*param[i] <========= Thsi is wrong
When I try to reference the array elements, I get the wrong value, so obviously something is wrong with my pointer dereferencing. It has been a while since I coded in C, so I can't see the obvious mistake.
Can someone please point it out?
You probably don't want to pass it via a pointer; when you use the type in the argument, it becomes a pointer anyway, and second level of indirection is less efficient.
If you do use the 'pointer to an array' notation, then you need parentheses to get the precedence correct:
if ((*param)[i] ...)
...
myString * is a pointer to a char array with 256 elements, i.e., param has type
char (*)[256]
so you have to dereference param first, then access its element.
By dereferencing param, you got the address of the first element of the array param points to.
(*param)[i] is then the ith element of the array in question.
// This is OK: an array can be treated as "char *", and vice versa
char myString[256];
void MyFunc(char * param)
{
int i;
for (i = 0; i < 256; i++)
{
if (param[i] ...
Q: I would like to make this more efficient and pass a pointer to the
char array
A: There's absolutely no difference in efficiency whether you pass "param[]" or "*param"
for (i = 0; i < 256; i++)
{
if (*param[i] <==== <========= Thsi is wrong
Yup - it's wrong. Again, "param[]" and "*param" should be treated the same way.
Same with or without the "typedef", too :)
Finally, here's the same program with the typedef:
typedef char myString[256];
void MyFunc(myString param)
// This is treated as "MyFunc(char param[256])"
// It is *identical* to "MyFunc(char * param)"
{
int i;
for (i = 0; i < 256; i++)
{
if (param[i] ....
use as below :
if (*(param +i) ...)
...
I want to scan a 2D array with the help of pointers and have written this code, could you tell me why the compiler gives errors?
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int i,j,n,a,b;
int (*(*p)[])[];
printf("\n\tEnter the size of the matrix in the form aXb\t\n");
scanf("%dX%d",&a,&b);
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
for(i=0;i<b;i++) {
p[i]=(int (*p)[a])malloc(a*sizeof(int));
printf("\t\bEnter Column %d\t\n");
for(j=0;j<a;j++)
scanf("%d",&p[i][j]);
}
return 0;
}
This statement has several problems:
p=(int (*(*p)[b])[a])malloc(b*sizeof(int (*p)[a]));
First, malloc returns a void*. You are casting that pointer using (int (*(*p)[b])[a]) which yields a value, not a data type. That isn't a valid cast, so that's one reason that the compiler is yelling at you. At this point, p hasn't been initialized so the de-referencing taking place here can crash your program if this statement was executed.
Inside your malloc call, you are using sizeof(int (*p)[a]). The statement int (*p)[a] isn't a valid C statement.
It seems that you are making this a bit more complex that it needs to be. There are two ways of building a 2D array. You can build an array using malloc(a * b * sizeof(int)) as Reinderien explains. You can also build a 1D array of pointers, each pointing to an array of type int. From your code, it seems you are trying to do the latter.
The easier way to do this would be something like this:
int **p;
... get input from user ...
// Declare an array of int pointers of length b
p = malloc(b * sizeof(int*));
// For each int* in 'p' ...
for (i = 0; i < b; ++i) {
// ... allocate an int array of length 'a' and store a pointer in 'p[i]' ..
p[i] = malloc(a * sizeof(int));
// ... and fill in that array using data from the user
printf("\t\bEnter Column %d\t\n");
for(j = 0; j < a; j++)
scanf("%d", &p[i][j]);
}
Using this method of building a 2D array allows you to use the syntax p[x][y]. Since p is a pointer-to-pointer, p[x] is a pointer to an array and p[x][y] is an item in the pointed-to array.
That's some pretty contorted syntax. Usually when you make a 2D array:
The declaration is simply int *p;
The allocation is simply p = malloc(a*b*sizeof(int));
You cannot write p[i][j]. You must do one of several things - either make a secondary array int **q that contains row pointers to be able to write q[i][j] (better performance and legibility), or write p[b*i + j] (fewer steps).
Additionally, note that:
Your printf will spew garbage due to the missing %d parameter.
Since C is not typesafe, using scanf will hide any errors in indirection that you may make.
About the closest thing I could think of that remotely resembles what you were trying to do:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
const int a = 3, b = 4;
int m[4][3];
int (*p[4])[3];
for (i = 0; i < b; i++)
{
p[i] = &m[i];
printf("\t\bEnter Column %d\t\n", i);
for (j = 0; j < a; j++)
{
int x;
scanf("%d", &x);
(*p[i])[j] = x;
}
}
return 0;
}
It compiles and functions as expected, but it's pointlessly complicated. p is an array of pointers to arrays.