I have a bunch of related arrays arr1, arr2, arr3. I pass these to a few functions, like foo.
int foo(int* arr1, int* arr2, int* arr3, ...) { ... }
The argument list starts to get pretty long, so I wanted to make a struct Bar to collect these related arrays in a single struct, like so:
struct Bar {
int* arr1;
int* arr2;
int* arr3;
};
This allows me to simplify foo into foo(struct Bar bar, ...) { ... }, which is great. But when I do this the execution time goes from 1m35 to 2m18, which is a slowdown 45%. Using pointers instead, like foo(struct Bar* bar, ...) is faster at 2m03, but still slower overall. All of these measurements were taken with gcc 12.2.0. I compiled an optimized build (-O3).
I understand that adding a layer of indirection is bound to slow the program down, but given that this is such a common pattern and the change is so slight, I expected that the compiler would optimize this indirection away.
I also wonder if there is anything I can do to tell the compiler what I'm doing. Kind of like how inline can be used to change how functions are compiled. If nothing else, I'm curious as to why this is apparently a hard thing for the compiler to recognize and optimize.
Thank you in advance!
P.S. Here's the full code, it's short enough to put here. It's before I added the struct and it finds a solution to the N queens problem on the torus. The three arrays I'm trying to put into a struct are cols, updiags, downdiags.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define N 31
int upDiag(int row, int col) {
int updiag = row + col;
if (updiag >= N)
updiag -= N;
return updiag;
}
int downDiag(int row, int col) {
int downdiag = row - col;
if (downdiag < 0)
downdiag += N;
return downdiag;
}
bool isSafeTorus(int* cols, int* updiags, int* downdiags, int row, int col, int updiag, int downdiag){
for(int i = 0; i < row; i++) {
if (cols[i] == col || updiags[i] == updiag || downdiags[i] == downdiag) {
return false;
}
}
return true;
}
bool solveNQUtil(int* cols, int* updiags, int* downdiags, int row){
/* If all queens are placed then return true */
if (row >= N)
return true;
/* try placing this queen in all coloms one by one */
for (int i = 0; i < N; i++) {
/* Check if the queen can be placed on board[row][i] */
int updiag = upDiag(row, i);
int downdiag = downDiag(row, i);
if (isSafeTorus(cols, updiags, downdiags, row, i, updiag, downdiag)) {
cols[row] = i;
updiags[row] = updiag;
downdiags[row] = downdiag;
/* place rest of queens */
if (solveNQUtil(cols, updiags, downdiags, row + 1))
return true;
/* If placing queen in board[i][col] no solution, remove queen*/
}
}
/* Queen can not be placed this row */
return false;
}
void main(){
int* cols = (int*)malloc(N * sizeof(int));
int* updiags = (int*)malloc(N * sizeof(int));
int* downdiags = (int*)malloc(N * sizeof(int));
if (solveNQUtil(cols, updiags, downdiags, 0) == false) {
printf("Solution does not exist");
}
for(int i = 0; i < N; i++) {
printf("%d\n", cols[i]);
}
}
Related
How can I return an array from a function, I am trying to perform (3*3)*(3*1) matrix multiplication using this translation function and how can i get an array out of it.
#include <stdio.h>
#include <math.h>
int* translation(int x, int y, int tx, int ty) {
static int res[3][1] = {0}, xy[3][1] = {{x},{y},{1}};
int tm[3][3] = {{1,0, tx}, {0,1,ty}, {0,0,1}};
for (int i = 0; i<3; i++) {
for (int j = 0; j<3; j++) {
res[i][0] += tm[i][j]*xy[j][0];
}
}
return res;
}
int main()
{
int *arr[3][1];
arr = translation(5, 5);
printf("%d %d %d", arr[0][0], arr[0][1], arr[0][2]);
return 0;
}
"How can I return an array from a function"
You can't.
The language has no such concept.
You'll have to return something including the length to give the user of the function the information. In C the idiomatic approach is to supply a pointer to the function and to get a value (via that pointer) in return:
size_t no_idea;
void function(void *data, &no_idea);
As a user of this function you'd have to read no_idea before judging.
you question is missing a lot of information like what you want to do with your code, the variable named xy isn't defined anywhere in your code, and so on...
but for clarification, if your result matrix is of unknown size, you can wrap your array into a struct, if you don't know what is the struct, you can refer to this small tutorial about struct in c, so your struct maybe look like something like this:
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int **arr;
}Array_t;
where arr is your matrix of unknown size which will be created dynamically and arrSize_x, arrSize_y are your matrix dimensions.
so in order to create a matrix of unknow size at compile time , you should create it dynamically in the heap memory using functions like calloc or malloc, although in C99, it allowed created arrays statically of unknown size during compile time but it's not the case with struct as the struct once defined, your array is created and you cannot do something like this:
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int arr[arrSize_x][arrSize_y];
}Array_t;
but if the size of the array is known you can do something like this:
typedef struct Array_t{
int arr[3][1];
}Array_t;
to create a dynamic array, you will find in the next example code something like this:
// rows are stored in heap memory and initiated with zeros
res.arr = (int**) calloc(res.arrSize_x, sizeof(int));
// columns are also stored in heap memory and initiated with zeros
for (int i = 0; i < res.arrSize_x; ++i) {
res.arr[i] = (int *) calloc(res.arrSize_y, sizeof(int));
}
where res.arr is a pointer pointing to an array of pointers and the next diagram may simplify my explanation where the next graph expresses the created matrix in heap memory for arr of size 3 x 1:
while if the size is known, so the explanation diagram may look like this:
and when you return, you can either return by value or by reference, but if you are going to return a struct by reference then you should declare it as static.
so you can do something like this (for clarification purposes, size of matrix is unknown):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int **arr;
}Array_t;
Array_t translation(int x, int y, int tx, int ty) {
// create a struct holding the array
Array_t res;
res.arrSize_x = 3;
res.arrSize_y = 1;
// rows are stored in heap memory and initiated with zeros
res.arr = (int**) calloc(res.arrSize_x, sizeof(int));
// columns are also stored in heap memory and initiated with zeros
for (int i = 0; i < res.arrSize_x; ++i) {
res.arr[i] = (int *) calloc(res.arrSize_y, sizeof(int));
}
res.arr[0][0] = 1;
res.arr[1][0] = 2;
res.arr[2][0] = 3;
return res;
}
int main()
{
Array_t array;
// 1, 2, 3, 4 are dummy parameters
array = translation(1, 2, 3, 4);
printf("elements are :\n");
for (int i = 0; i < array.arrSize_x; ++i) {
for (int j = 0; j < array.arrSize_y; ++j) {
printf("%d\t", array.arr[i][j]);
}
printf("\n");
}
return 0;
}
and this is the output:
elements are :
1
2
3
but if size of matrix is known then you can do something like this (for clarification purposes, size of matrix is known):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct Array_t{
int arr[3][1];
}Array_t;
Array_t translation(int x, int y, int tx, int ty) {
// create a struct holding the array
Array_t res;
res.arr[0][0] = 1;
res.arr[1][0] = 2;
res.arr[2][0] = 3;
return res;
}
int main()
{
Array_t array;
// 1, 2, 3, 4 are dummy parameters
array = translation(1, 2, 3, 4);
printf("elements are :\n");
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 1; ++j) {
printf("%d\t", array.arr[i][j]);
}
printf("\n");
}
return 0;
}
and this is the ouput:
elements are :
1
2
3
I have an exam and the teacher want to do a problem. It sound like this.
a)Reading information about an array (the function returns a structure associated with an array)
b)Reading the elements of an array (the function receives as parameters two integers and a pointer to FILE and returns a pointer to pointer to integer)
the point a) is Matrix* infoM.
the point b) is int** readM
And I get an error with the returning type
enter code here
#include <stdio.h>
#include <stdlib.h>
typedef struct Matrix{
int rows;
int cols;
int** data;
}Matrix;
Matrix* infoM( int n_rows, int n_cols)
{Matrix Matrix;
int i;
Matrix.rows = n_rows;
Matrix.cols = n_cols;
Matrix.data = (int**)malloc(sizeof(int*) * n_rows);
if(Matrix.data == 0)
{
fprintf(stderr, "err");
exit(EXIT_FAILURE);
}
for(i=0;i<n_rows;i++)
{
*(Matrix.data+i) = (int*)malloc(sizeof(int)*n_cols);
if(*(Matrix.data+i) == 0)
{
fprintf(stderr,"err");
exit(EXIT_FAILURE);
}
}
struct Matrix *m;
m = &Matrix;
return m;
}
int** readM(int n_rows, int n_cols, FILE *in)
{
Matrix* matrix = infoM(n_rows,n_cols);
int i,j;
for(i=0; i<n_rows; i++)
{
for(j=0; j<n_cols; j++)
{
fscanf(in, "%d",*(matrix->data+i)+j);
}
}
return matrix;
}
I would use a flexible array member to remove double-pointer - and additional overhead (it removes one level of indirection). Additionally, it simplifies malloc/free (only one needed).
To access data use an array pointer.
typedef struct Matrix{
size_t rows;
size_t cols;
int data[];
}Matrix;
Matrix *createM(size_t rows, size_t cols)
{
Matrix *m = malloc(sizeof(*m) + cols * rows * sizeof(m -> data[0]));
return m;
}
Matrix *initM(Matrix *m)
{
int (*data)[m -> cols] = (int (*)[m -> cols])m -> data;
for(size_t row = 0; row < m -> rows; row++)
{
for(size_t col = 0; col < m -> cols; col++)
{
data[row][col] = rand();
}
}
return m;
}
Use correct types for sizes.
C has a notion of lifetime for variables. Automatic variables (declared in a block of function) reach their end of life at the end of the block (or function...) where they are declared in. And using an object passed its end of life explicetely invokes Undefined Behaviour (close to hell for C programmers).
For that reason you cannot return the address of a local variable. It is called a dangling pointer (Google that word for additional details...).
But C allows to return a whole structure. So a minimal modification of your code could be:
...
Matrix infoM( int n_rows, int n_cols)
{Matrix Matrix;
int i;
Matrix.rows = n_rows;
...
return Matrix;
}
Matrix readM(int n_rows, int n_cols, FILE* in)
{
Matrix matrix = infoM(n_rows, n_cols);
int i, j;
for (i = 0; i < n_rows; i++)
{
for (j = 0; j < n_cols; j++)
{
fscanf(in, "%d", matrix.data[i] + j); // more C idiomatic...
}
}
return matrix;
}
For the same reason, readM is not allowed to return a pointer inside a local object, because it would be a dangling pointer, but you can again return the struct itself.
I'm trying to build a Boolean function to check if two unsorted arrays have the same elements. But every time I try to debug the program,I keep getting an error "Expression must have a pointer to object type". I have tried everything. Nothing seem to be working. Can anyone please let me know what I am doing wrong?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include<stdbool.h>
bool haveSameElems(arr1, arr2, size);
void main()
{
int size;
scanf("%d", &size);
int* arr1 = (int*)calloc(size, sizeof(int));
for (int i = 0; i < size; i++)
{
scanf("%d ", &arr1[i]);
}
int* arr2 = (int*)calloc(size, sizeof(int));
for (int i = 0; i < size; i++)
{
scanf("%d ", &arr2[i]);
}
bool ans = haveSameElems(arr1, arr2, size);
printf("%s", ans ? "true" : "false");
}
bool haveSameElems(arr1, arr2, size)
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
if (arr1[i] == arr2[j]) // I keep getting the error here
{
return true;
}
}
}
}
Your function declaration bool haveSameElems(arr1, arr2, size) is implicitly the same as bool haveSameElems(int arr1, int arr2, int size), per Frankie_C. To use arr1 and arr2 as arrays, they must be declared as pointers: bool haveSameElems(int *arr1, int *arr2, int size). So you need to add those two asterisks in both the function declaration at the top of your code and in the function definition it corresponds to. It’s good practice always explicitly to write types and not rely on the old K&R style implicit int types Frankie_C wrote about in his comment. You can read more about it in the bottom box here and in the “subscript” section here.
You also need a return false at the end of haveSameElems, and main must return type int if you’re using an older C complier. See here.
I'm trying to generate an array that increases in size as a while loop iterates. I know a pointer has something to do with the solution. Please look at the code below.
#include <stdio.h>
int main () {
int x = 0;
int *F = malloc(sizeof(int)); //I want F to start out as :-
F[0] = 1; // 1 by 1
F[1] = 2; // 1 by 2 such that it increases in size when assigned
int now = 2;
int evenSum = 2;
while (x <= 40000) {
F[now] = F[now-1] + F[now-2];
x = F[now];
if (F[now] % 2)
{
evenSum += F[now];
}
++now;
}
printf("The outcome is %d\n", evenSum);
//free(F);
// Yes this is problem 2 of euler challenge, i already got a working static model
}
Many Thanks in Advance
EDIT
What I'm actually looking for is the sum of all the even fib's up to a cut off limit of 40M. I could (what i did first time) sum the even numbers as i encounter them during the fib sequence. This meant i did not keep a array of some arbitary size. The purpose of this post is to create a growing memory that just keeps on consuming memory until it gets to the answer.
The following is the code I got from the brilliant answer that was given.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
struct vector {
size_t size;
int *data;
};
void vector_resize(struct vector *vector, size_t size) {
if (vector->size >= size)
return;
while (vector->size < size)
vector->size *= 2;
vector->data = realloc(vector->data, sizeof(int) * vector->size);
assert(vector->data != NULL);
}
struct vector * vector_init() {
struct vector *vector = malloc(sizeof(*vector));
vector->size = 4;
vector->data = malloc(vector->size * sizeof(int));
return vector;
}
void vector_free(struct vector *vector) {
free(vector->data);
free(vector);
}
void vector_put(struct vector *vector, size_t index, int data) {
vector_resize(vector, index+1);
vector->data[index] = data;;
}
int vector_get(struct vector *vector, size_t index) {
vector_resize(vector, index+1);
return vector->data[index];
}
int main() {
struct vector *vector = vector_init();
int fibNow = 0;
int now = 2;
vector_put(vector, 0, 1);
vector_put(vector, 1, 2);
int evenSum = 2;
while (fibNow <= 4000000) {
fibNow = vector_get(vector, (now-1)) + vector_get(vector, (now-2));
vector_put(vector, now, fibNow);
if (fibNow % 2 == 0) {
evenSum += fibNow;
}
++now;
}
printf("The outcome is %d\n", evenSum);
// vector_put(vector, 0, 5);
// vector_put(vector, 9, 2);
// int i;
// for (i=0; i<10; ++i)
// printf("index 0: %d\n", vector_get(vector, i));
vector_free(vector);
}
So, In C we aren't allowed to overload the operator[]. But we could still create an object that functions like your request:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
struct vector {
size_t size;
int *data;
};
void vector_resize(struct vector *vector, size_t size) {
if (vector->size >= size)
return;
while (vector->size < size)
vector->size *= 2;
vector->data = realloc(vector->data, sizeof(int) * vector->size);
assert(vector->data != NULL);
}
struct vector * vector_init() {
struct vector *vector = malloc(sizeof(*vector));
vector->size = 4;
vector->data = malloc(vector->size * sizeof(int));
return vector;
}
void vector_free(struct vector *vector) {
free(vector->data);
free(vector);
}
void vector_put(struct vector *vector, size_t index, int data) {
vector_resize(vector, index+1);
vector->data[index] = data;;
}
int vector_get(struct vector *vector, size_t index) {
vector_resize(vector, index+1);
return vector->data[index];
}
int main() {
struct vector *vector = vector_init();
vector_put(vector, 0, 5);
vector_put(vector, 9, 2);
for (int i=0; i<10; ++i)
printf("index 0: %d\n", vector_get(vector, i));
vector_free(vector);
}
Additionally, it's fun to look at a C++ version of what this could be. C++ makes this look far more like your original code, because we can overload operator[] for arbitrary objects.
#include <cstdio>
#include <vector>
template <typename T>
class auto_growing_vector {
private:
std::vector<T> data;
public:
T & operator[](size_t index) {
if (index >= data.size())
data.resize(index + 1);
return data[index];
}
};
int main() {
auto_growing_vector<int> vector;
vector[0] = 5;
vector[9] = 2;
for (int i=0; i<10; ++i)
printf("index 0: %d\n", vector[i]);
}
In general, realloc should do the trick for you. Example (this is just a snippet - you will need to do the rest yourself):
int *F;
F = malloc(2 * sizeof *F); // note you have to start with 2 elements for your code, not 1
F[0] = 1;
F[1] = 2;
// when you know you need to increase the size of F:
temp = realloc(F, n * sizeof *F); // where n is the new size in elements
if(temp != NULL) F = temp; // note that the block may have moved to a new place!
else {
printf("unable to grow the array to %d elements!\n", n);
free(F);
exit(0);
}
Of course for this problem you don't need to keep all the Fibonacci numbers - just the last two. This actually suggests a much simpler code. Let me start if for you, and see if you can finish it (since you are doing the Euler problems, which are all about figuring it out for yourself):
int first = 1;
int second = 1; // usually you start with 1,1,2,3,...
int temp, current;
int count;
int N = 4000; // where we stop
for(count = 2; count < N; count ++) {
current = first + second;
first = second;
second = current;
}
If you look closely, you can get even more efficient that this (hint, you really only need to keep one older value, not two...)
Reading the comments, if you want all the numbers in memory, you should just allocate enough space from the outset:
F = malloc(4000 * sizeof *F);
and no further manipulations are needed. Make sure your last index is 3999 in that case (since arrays are zero indexed).
I One way would be to use 2D array int[n][n], whith a lot of unused space
II Easier way would be to expend array size in every iteration by realocate function.
Just in that case, either:
a) every element of the original array would be a pointer to a new array of length i (i beeing iteration number), you would then realocate the original array to make size for new pointer, then allocate i*sizeof(int) of new memory for that new array that pointer would point to.
b) You would make linearized traingular matrix in which the original array will hold just numbers, not pointers. In every iteration you would expand it's size for i new elements. Linearized trangular matrix is a onedimensional array of numbers in which data is saved like this:
ordinary matrix: (/ = wasted memory)
A///
BC//
DEF/
GHIJ
linarized triangular matrix
ABCDEFGHIJ
You can acces linerized triangular matrix element E with coordinates [y,x] = [2,1] (element 'A' taken for origin) like
sum=0;
for(iy=0;iy<y;iy++)
for(ix=0;ix<=y && ix<x;ix++) sum++;
//myLinMatr[sum]=='E'
I am new to C and during my learning I want to return a two dimensional array from a function, so that I can use it in my main program. Can anyone explain me the same with example. Thanks in advance.
It depends how it is implemented. You can either work with just a one-dimensional array where you know the length of each (row) and the next row begins immediately after the previous one. OR, you can have an array of pointers to arrays. The extra cost though is you need to de-reference two pointers to get to one element of data.
// 2D array of data, with just one array
char* get_2d_ex1(int rows, int cols) {
int r, c, idx;
char* p = malloc(rows*cols);
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
idx = r*cols + c; // this is key
p[idx] = c; // put the col# in its place, for example.
}
}
return p;
}
Declare your function as returning a pointer to a pointer. If we use int as an example:
int **samplefunction() {
int** retval = new int*[100];
for (int i = 1; i < 100; i++) {
retval[i] = new int[100];
}
// do stuff here to retval[i][j]
return retval;
}
Here's an example of how you might create, manipulate and free a "2d array":
#include <stdlib.h>
#define ROWS 5
#define COLS 10
int **create_2d_array(size_t rows, size_t cols)
{
size_t i;
int **array = (int**)malloc(rows * sizeof(int*));
for (i = 0; i < rows; i++)
array[i] = (int*)malloc(cols * sizeof(int));
return array;
}
void free_2d_array(int **array, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
free(array[i]);
free(array);
}
int main(void)
{
int **array2d = create_2d_array(ROWS, COLS);
/* ... */
array2d[3][4] = 5;
/* ... */
free_2d_array(array2d, ROWS, COLS);
return 0;
}
To create a "2d array"/matrix, all you have to do is create a dynamic array of pointers (in this case int*) of the size of the rows/width:
int **array = (int**)malloc(rows * sizeof(int*));
Then you set each of those pointers to point to a dynamic array of int of the size of the columns/height:
array[i] = (int*)malloc(cols * sizeof(int));
Note that the casts on malloc aren't required, it's just a habit I have.