Is it possible to create statically in C a 2d array of pointers to 2d arrays, like:
#define m 4
#define n 4
#define p 2
#define q 2
char arr1[m][n] = {{0}};
char arr2[m][n] = {{0}};
char (*parr[m][n])[p][q] = {{&arr1, 0, &arr2, 0}};
int main() {
return 0;
}
The 2d array of pointers parr is sparse, with some values to 0 (NULL), which is why I don't want to use a 4d array in the first place.
This compiles, but I get the following warning:
warning: initialization from incompatible pointer type
With the following command:
gcc -Wall -Wextra -pedantic -std=c99 test.c
What is wrong?
The problem is that when you declare pointers, arrays and array pointers, the [] takes precedence over * unless you add parenthesis. This is why you declare an array pointer as (*parr)[] rather than *parr[], since the latter gives an array of pointers instead.
Similarly, when declaring a pointer to a 2D array, you would type (*parr)[m][n]. So it seems logical that an array of 2D-array pointers should be declared as ((*parr)[m][n])[p][q]). But the outer parenthesis here actually does nothing, that expression is equivalent to (*parr)[m][n][p][q]. And that's an array pointer to a 4D array! Which is why you get compiler warnings.
Now what you actually want is to get an array of array pointers to 2D arrays, is something like char (*parr[p][q])[m][n]. Which looks rather insane, nobody will understand a declaration like that.
The only sane way to write code like this is through typedefs:
typedef char arr_t[m][n];
arr_t arr1 = {{0}};
arr_t arr2 = {{0}};
arr_t* parr[p][q] =
{
{&arr1, 0},
{&arr2, 0}
};
I think what you meant to do is the following:
char arr1[m][n] = {{0}};
char arr2[m][n] = {{0}};
typedef char (*some_type)[n]; // type of arr1 and arr2
some_type parr[p][q] = {{arr1, NULL}, {arr2, NULL}}; //array containing arr1 and arr2
You can then access parr e.g by
printf("%c\n", parr[0][0][0][0]);
which will print arr1[0][0].
In the declaration of parr I think you meant to use p and q as its dimensions:
$ cat test.c
#include <stdio.h>
#define m 4
#define n 4
#define p 2
#define q 2
char arr1[m][n] = {{0}};
char arr2[m][n] = {{0}};
char (*parr[p][q])[m][n] = {{&arr1, NULL}, {&arr2, NULL}};
int main(void)
{
printf("%d\n", (*parr[0][0])[0][0]);
return 0;
}
This compiles cleanly with GCC 4.8.2:
$ gcc --version
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -ansi -fsanitize=address -g -pedantic -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -o test test.c
$
Here would be my solution -- i prefer using static 1D arrays rather than static 2D arrays due pointer arithmetic (i like to keep things simple):
PS. i would suggestin using m!=n and p!=q for testing, so you can catch possible indexing errors!
#include <stdio.h>
#define m 4
#define n 4
#define p 2
#define q 2
char arr1[m*n] = {0};
char arr2[m*n] = {0};
typedef char array_2d[m][n];
char* parr[p][q] = { {(char*)arr1, NULL}, { (char*)arr2, NULL} };
int main()
{
for (int i = 0; i < m; i ++ )
for (int j = 0; j < n; j ++ )
{
arr1[i*n + j] = i + j;
arr2[i*n + j] = i - j;
}
for (int i = 0; i < m; i ++ )
{
for (int j = 0; j < n; j ++ )
{
char* arr1_ptr = parr[0][0];
char* arr2_ptr = parr[1][0];
printf("%d", (int)(arr1_ptr[i*n + j] - arr2_ptr[i*n + j] ));
}
printf("\n");
}
return 0;
}
Related
I have a SWIG file to get output int array from .C file and pass it to Perl so that i can print array value in Perl. There is a Function in C source, which will return an int array. When I'm tried to print those values in Perl, it is not printing Array value.
I have this swig file called perl.i
This is what I try:
#ifdef SWIGPERL
%module aticara
%{
#include "include.h"
extern int myfunction();
%}
%typemap(out) int [ANY] {
}
int myfunction();
#endif
I don't know what to write inside typemap.
The perl script called test.pl, when it runs, but the array is empty:
Here is my test.pl
#!/usr/bin/perl
use aticara;
use feature qw(say);
my $arr = aticara::myfunction();
my $list = $arr;
my $i = 0;
for ( #$list ) {
say "$i: '$_'";
$i=$i+1;
}
It is printing empty.
I don't no what i am missing and where. But one thing i can tell is that it is from my swig file.
And also i am sharing my C file where it will return an Array list.
Here is my c file:
int myfunction()
{
int a[5];
a[0] = 45;
a[1] = 4;
a[2] = 8;
a[3] = 9;
a[4] = 1;
return *a;
}
Expected output in Perl is:
0: 45
1: 4
2: 8
3: 9
4: 1
But i can't able to get this output. I don't no that much in swig.
If someone help me to get out, that will be great.
Thanks in Advance.
You should return a pointer to an int array and not the content of the first element of the local array a. Instead create the array using malloc() and make use of the SWIG ret typemap to free it up. Then also create an out typemap to convert the returned array to a Perl array. Here is an example of how it can be done:
example.i
%module example
%{
#include "example.h"
%}
%typemap(out) int * {
AV *myav;
SV **svs;
int len = 0;
/* Figure out how many elements we have */
while ($1[len])
len++;
svs = (SV **) malloc(len*sizeof(SV *));
int i;
for (i = 0; i < len ; i++)
svs[i] = newSViv($1[i]);
myav = av_make(len, svs);
free(svs);
$result = newRV_noinc((SV*)myav);
sv_2mortal($result);
argvi++;
}
%typemap(ret) int * %{
free($1);
%}
%include "example.h"
example.h
#include <stdlib.h>
extern int *myfunction();
example.c
#include "example.h"
int *myfunction()
{
int *a = (int *) malloc( 5*sizeof(int) );
a[0] = 45;
a[1] = 4;
a[2] = 8;
a[3] = 9;
a[4] = 1;
return a;
}
test.pl
use feature qw(say);
use strict;
use warnings;
use example;
my $arr = example::myfunction();
my $i = 0;
for ( #$arr ) {
say "$i: '$_'";
$i++;
}
Compilation (Ubuntu 16.10 with perlbrew):
swig -perl5 example.i
perl_dir=~/perlbrew/perls/perl-5.24.1/lib/5.24.1/x86_64-linux/CORE
gcc -fpic -c example.c
gcc -fpic -c -Dbool=char -D_GNU_SOURCE -I"$perl_dir" example_wrap.c
gcc -shared example.o example_wrap.o -o example.so
Running
$ perl test.pl
0: '45'
1: '4'
2: '8'
3: '9'
4: '1'
I'm trying to learn how to copy a space in memory that was allocated with malloc. I'm assuming the best way to go about this would be to use memcpy.
I am more familiar with Python. The equivalent of what I'm trying to do in Python would be:
import copy
foo = [0, 1, 2]
bar = copy.copy(foo)
Here is was I have so far.
/* Copy a memory space
* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
// initialize a pointer to an array of spaces in mem
int *foo = malloc(3 * sizeof(int));
int i;
// give each space a value from 0 - 2
for(i = 0; i < 3; i++)
foo[i] = i;
for(i = 0; i < 3; i++)
printf("foo[%d]: %d\n", i, foo[i]);
// here I'm trying to copy the array of elements into
// another space in mem
// ie copy foo into bar
int *bar;
memcpy(&bar, foo, 3 * sizeof(int));
for(i = 0; i < 3; i++)
printf("bar[%d]: %d\n", i, bar[i]);
return 0;
}
The output of this script is as follows:
foo[0]: 0
foo[1]: 1
foo[2]: 2
Abort trap: 6
I'm compiling the script with gcc -o foo foo.c. I'm on a 2015 Macbook Pro.
My questions are:
Is this the best way to copy an array that was created with malloc?
What does Abort trap: 6 mean?
Am I just misunderstand what memcpy does or how to use it?
Kind regards,
Marcus Shepherd
The variable bar has no memory allocated to it, it is just an uninitialised pointer.
You should do that as you did with foo earlier
int *bar = malloc(3 * sizeof(int));
And then you need to drop the & address-of operator as
memcpy(bar, foo, 3 * sizeof(int));
I want to manipulate existing 2D arrays of doubles directly in LuaJIT by passing a pointer to the script. I see it isn't possible to create pointers to existing data. Can I pass a pointer to an existing array of primitives from C to LuaJIT and read/write from there? I know the size of the array and data so just need to be able read/write the memory.
Sure you can!
Here is a small test script, where I allocate and fill an array on the C side and I get a pointer in lua through a function.
// test.c
// gcc -std=c99 -O3 -Wall -fPIC -shared test.c -o libtest.so
#include <stdio.h>
#include <stdlib.h>
#define SIZE_A 10
double** get_pointer()
{
double** a = malloc(SIZE_A * sizeof(*a));
for (int i = 0; i < SIZE_A; ++i) {
a[i] = malloc(SIZE_A * sizeof(*a[i]));
for (int j = 0; j < SIZE_A; ++j) {
a[i][j] = i*SIZE_A + j;
printf("%.1f ", a[i][j]);
}
printf("\n");
}
printf("&a_c = %p\n", (void*)a);
return a;
}
And the Lua script:
local ffi = require "ffi"
local testLib = ffi.load("./libtest.so")
ffi.cdef[[
double** get_pointer();
]]
local ptr = ffi.new("double**")
ptr = testLib.get_pointer()
print(ptr)
local size_a = 10
for i=0,size_a-1 do
for j=0,size_a-1 do
io.write(ptr[i][j], ' ')
end
io.write('\n')
end
for i=0,size_a-1 do
for j=0,size_a-1 do
ptr[i][j] = 2 * ptr[i][j]
end
end
for i=0,size_a-1 do
for j=0,size_a-1 do
io.write(ptr[i][j], ' ')
end
io.write('\n')
end
I'm trying to pass in an array of integers into my program. Is there a better way to convert it to integers? I'm currently getting an error: "Variable sized object may not be initialized"
for(i = 0; i < argc; i++)
{
int arr[i] = atoi(argv[i]);
}
Assuming argc and argv are the arguments passed to main, it is unlikely that argv[0] is something that you want to convert into an integer. argv[0] usually contains the name of the program.
Your code snippet is declaring an array local to the loop body. What you likely want is an array defined outside the loop body, and you want to assign to individual array elements within the loop body.
int arr[argc];
for(i = 1; i < argc; i++)
{
arr[i] = atoi(argv[i]);
}
You are declaring your array arr every time you loop.
change your loop like this:
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
int arr[argc];
int i=0;
for(i = 0; i < argc-1; i++)
{
arr[i] = atoi(argv[i+1]);
printf("arr[%d] = %d\n",i,arr[i]);
}
return 0;
}
Here is the output:
Sukhvir#Sukhvir-PC ~
$ gcc -Werror -Wall -g -o test test.c
Sukhvir#Sukhvir-PC ~
$ ./test 3 4 5
arr[0] = 3
arr[1] = 4
arr[2] = 5
I have the following c function declaration:
float Sum2d( const unsigned int nRows, const unsigned int mCols, float arr[nRows][mCols] )
{
float sumAll = 0;
// I would like to make this change illegal!
arr[0][0] = 15;
for (int i = 0; i < nRows; i++)
for (int j = 0; j < mCols; j++)
sumAll += arr[i][j];
return sumAll;
}
Using the code:
int main()
{
// define a 2d float array
float myArr2d[3][2] = {{1,2}, {3,4}, {5,6}};
// calculate the sum
float sum = Sum2d(3, 2, myArr2d);
// print the sum
printf("%f\n", myOpResult);
// return 1
return 1;
}
This function works well, yet there's one problem: the elements of arr can be altered in the Sum2d() function.
How can I change Sum2d()'s prototype to prevent any changes to arr's elements?
Multidimensional arrays with const qualification are difficult to handle. Basically you have the choice to cast non-const arrays at every call side, to avoid such const arrays as arguments completely, or to deviate by using some sophisticated macros. This is a longer story, you may read it up here.
I don't know what compiler you're using, but that doesn't compile for me as C or C++.
But regardless, just making arr const should suffice.
Change the prototype of the function to use const with float
Also you have specified nRows / nCols in array argument, which is not allowed in C. If you don't know the bounds of array, use double pointer.
This approach doesn't prevents typecasting in the function.
#include <stdio.h>
float Sum2d( const unsigned int nRows, const unsigned int mCols, const float arr[][2] )
{
float sumAll = 0;
// I would like to make this change illegal!
//arr[0][0] = 15;
for (int i = 0; i < nRows; i++)
for (int j = 0; j < mCols; j++)
sumAll += arr[i][j];
return sumAll;
}
int main()
{
// define a 2d float array
float myArr2d[3][2] = {{1,2}, {3,4}, {5,6}};
// calculate the sum
float sum = Sum2d(3, 2, (const float (*)[2])myArr2d);
// print the sum
printf("%f\n", sum);
// return 1
return 1;
}
Since you are using following command line i suppose:
gcc <file.c> -o out -std=c99
Running on Debian Squeeze
$ gcc array.c -o array -std=c99
$ gcc --version
gcc (Debian 4.4.5-8) 4.4.5
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.