Array access, pointer confusion - c

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) ...)
...

Related

Allocate array of struct and then access it using an array method give compilation error

I allocate structs array and tried to access elements using the array indexer syntax ptr[i]->a but it doesn't work.
On the other hand, when I use pointer arithmetic (ptr + i)->a it works.
The reason why I try to access using the array method is that I thought that struct allocated continuously in heap memory.
Is my assumption wrong?
Could anyone tell me the reason?
#include <stdlib.h>
typedef struct sample_t{
int a;
} Sample;
void Function(Sample *ptr)
{
int i;
Sample *tmp = ptr;
for(i = 0; i<100; i++)
{
(tmp + i)->a = i; //work!!
}
for(i = 0; i<100; i++)
{
ptr[i]->a = i; //doesn't work!!
}
}
int main(void)
{
Sample *arr = (Sample *)calloc(100, sizeof(Sample));
Function(arr);
}
My compiler says:
error: base operand of '->' has non-pointer type 'Sample' {aka 'sample_t'}
I'm sure yours says something similar. It's complaining about this:
ptr[i]->a = i;
So it's saying ptr[i] is not a pointer (which -> requires). And ptr[i] is not a pointer because ptr[i] in C is equivalent to *(ptr + i) which means the dereferencing of the incremented pointer already happened, so you'd need this instead:
ptr[i].a = i;
An array subscript expression is automatically dereferenced for you, so you don't need to use -> to access members, use . instead.
Because ptr[offset] is the same as *(ptr + offset) (note the required dereference * in the latter, but not the former).
So change this:
ptr[i]->a = i;
To this:
ptr[i].a = i;
BTW, when working with dynamically-allocated arrays in C you should always keep the length of the array with the array-pointer itself (in C++ you'd use std::array for this). Don't forget to use size_t for the length instead of int.
e.g.
void Function( size_t n, Sample* arr )

Incompatible parameter types?

I want to use another function to print the contents of an array.
When I run the code I get "IntelliSense: argument of type "int (*)[3][3]" is incompatible with parameter of type "int *(*)[3]"
This is my function:
void display(int *p[N_ROWS][N_COLS]) {
int i, j;
for (i = 0; i < N_ROWS; i++) {
for (j = 0; j <N _COLS; j++) {
printf("%i", p[i][j]);
}
}
}
I defined N_ROWS and N_COLS
and in my main function I declare my array and then call the function
{
int Array[N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(&Array);
}
Aren't both my parameters type int(*)[3][3] or am I missing something?
Your prototype for display is incorrect, as well as your call syntax: you define display to take a 2D array of pointers to int, whereas you just want a 2D array if int, as you pass a pointer to the array in main where you just want to pass the array, decaying as a pointer to its first element.
Here is a simpler version:
void display(int p[N_ROWS][N_COLS]) {
int i, j;
for (i = 0; i < N_ROWS; i++) {
for (j = 0; j < N_COLS; j++) {
printf("%i", p[i][j]);
}
}
}
Note however that p above can have any number of rows, N_ROWS is ignored in the prototype, equivalent to void display(int (*p)[N_COLS]).
Note also that your printf will output the matrix values without any separation. This might not be your intent.
And from main:
{
int Array[N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(Array);
}
Much of this has already been explained in comments to your question.
Your definition of display:
void display(int*p[N_ROWS][N_COLS])
{
This says p will be an array N_ROWS of array N_COLS of pointers to int.
When you call display:
int Array [N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(&Array);
You are passing in the address of Array, thus it is a pointer to an array N_ROWS of array N_COLS of int.
To make the definition of display match the way you are calling it:
void display(int (*p)[N_ROWS][N_COLS])
{
The parentheses make the * associate with p first. Since p is a pointer to an array of array of int, getting to the int requires an extra dereference:
printf("%i\n", (*p)[i][j]);
Defining display to take a pointer to an array means that the size of the array is bound to the type parameter, and thus display knows exactly the dimensions of the array.
An alternative means would be to define display to take the dimension of the array as a second parameter.
void display(int p[][N_COLS], int n_rows)
{
In this case the p parameter is a pointer to an array N_COLS of int. An array of T when used in most expressions will decay to a value of type pointer to T equal to the address of its first element. Thus, you could call this second version of display like this:
int Array [N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(Array, N_ROWS);
The advantage of this second approach is that display can work with arrays that have fewer or more than N_ROWS. The disadvantage is that it is up to the caller to pass in the right number of rows.
You might think that the following declaration would give you complete type safety:
void display(int p[N_ROWS][N_COLS])
{
But, the array syntax in C for function parameters cause the size information for p to be ignored, and becomes equivalent to int p[][N_COLS], which in turn is treated as int (*p)[N_COLS].

warning: assignment makes integer from pointer without a cast in C

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];

Returning a two-dimensional array in C?

I recently started programming C just for fun. I'm a very skilled programmer in C# .NET and Java within the desktop realm, but this is turning out to be a bit too much of a challenge for me.
I am trying to do something as "simple" as returning a two-dimensional array from a function. I've tried researching on the web for this, but it was hard for me to find something that worked.
Here's what I have so far. It doesn't quite return the array, it just populates one. But even that won't compile (I am sure the reasons must be obvious to you, if you're a skilled C programmer).
void new_array (int x[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
return x;
}
And usage:
int x[n][n];
new_array(x);
What am I doing wrong? It should be mentioned that n is a constant that has the value 3.
Edit: Here's a compiler error when trying to define the constant: http://i.imgur.com/sa4JkXs.png
C does not treat arrays like most languages; you'll need to understand the following concepts if you want to work with arrays in C.
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. This result is not an lvalue; it cannot be the target of an assignment, nor can it be an operand to the ++ or -- operators.
This is why you can't define a function to return an array type; the array expression will be converted to a pointer type as part of the return statement, and besides, there's no way to assign the result to another array expression anyway.
Believe it or not, there's a solid technical reason for this; when he was initially developing C, Dennis Ritchie borrowed a lot of concepts from the B programming language. B was a "typeless" language; everything was stored as an unsigned word, or "cell". Memory was seen as a linear array of "cells". When you declared an array as
auto arr[N];
B would set aside N "cells" for the array contents, along with an additional cell bound to arr to store the offset to the first element (basically a pointer, but without any type semantics). Array accesses were defined as *(arr+i); you offset i cells from the address stored in a and dereferenced the result. This worked great for C, until Ritchie started adding struct types to the language. He wanted the contents of the struct to not only describe the data in abstract terms, but to physically represent the bits. The example he used was something like
struct {
int node;
char name[14];
};
He wanted to set aside 2 bytes for the node, immediately followed by 14 bytes for the name element. And he wanted an array of such structures to be laid out such that you had 2 bytes followed by 14 bytes followed by 2 bytes followed by 14 bytes, etc. He couldn't figure out a good way to deal with the array pointer, so he got rid of it entirely. Rather than setting aside storage for the pointer, C simply calculates it from the array expression itself. This is why you can't assign anything to an array expression; there's nothing to assign the value to.
So, how do you return a 2D array from a function?
You don't. You can return a pointer to a 2D array, such as:
T (*func1(int rows))[N]
{
T (*ap)[N] = malloc( sizeof *ap * rows );
return ap;
}
The downside to this approach is that N must be known at compile time.
If you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you could do something like the following:
void func2( size_t rows, size_t cols, int (**app)[cols] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...; // the parens are necessary
...
}
If you don't have variable-length arrays available, then at least the column dimension must be a compile-time constant:
#define COLS ...
...
void func3( size_t rows, int (**app)[COLS] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...;
}
You can allocate memory piecemeal into something that acts like a 2D array, but the rows won't necessarily be contiguous:
int **func4( size_t rows, size_t cols )
{
int **p = malloc( sizeof *p * rows );
if ( p )
{
for ( size_t i = 0; i < rows; i++ )
{
p[i] = malloc( sizeof *p[i] * cols );
}
}
return p;
}
p is not an array; it points to a series of pointers to int. For all practical purposes, you can use this as though it were a 2D array:
int **arr = foo( rows, cols );
...
arr[i][j] = ...;
printf( "value = %d\n", arr[k][l] );
Note that C doesn't have any garbage collection; you're responsible for cleaning up your own messes. In the first three cases, it's simple:
int (*arr1)[N] = func(rows);
// use arr[i][j];
...
free( arr1 );
int (*arr2)[cols];
func2( rows, cols, &arr2 );
...
free( arr2 );
int (*arr3)[N];
func3( rows, &arr3 );
...
free( arr3 );
In the last case, since you did a two-step allocation, you need to do a two-step deallocation:
int **arr4 = func4( rows, cols );
...
for (i = 0; i < rows; i++ )
free( arr4[i] )
free( arr4)
Your function return void, so the return x; line is superfluous. Aside from that, your code looks fine. That is, assuming you have #define n 3 someplace and not something like const int n = 3;.
You can't return an array in C, multidimensional or otherwise.
The main reason for this is that the language says you can't. Another reason would be that generally local arrays are allocated on the stack, and consequently deallocated when the function returns, so it wouldn't make sense to return them.
Passing a pointer to the array in and modifying it is generally the way to go.
To return (a pointer to) a newly-created array of dimensions known at compile time, you can do this:
#define n 10 // Or other size.
int (*new_array(void))[n]
{
int (*x)[n] = malloc(n * sizeof *x);
if (!result)
HandleErrorHere;
for (int i = 0; i < n; ++i)
for (int o = 0; i < n; ++o)
x[i][o] = InitialValues;
return x;
}
…
// In the calling function:
int (*x)[n] = new_array();
…
// When done with the array:
free(x);
If the size is not known at compile time, you cannot even return a pointer to an array. C does support variable-length arrays but not in the return types of functions. You could instead return a pointer to a variable-length array through a parameter. That requires using a parameter that is a pointer to a pointer to an array of variable length, so it gets somewhat messy.
Also, the preferred choices between allocating an array in the caller dynamically, allocating an array in the caller automatically, allocating an array in the called function dynamically and using variable-lengths arrays or fixed-length arrays or even one-dimensional arrays with manual indexing depend on context, including what how large the array might be, how long it will live, and what operations you intend to use it for. So you would need to provide additional guidance before a specific recommendation could be made.
In C there's only pass/return by value (no pass by reference). Thus the only way of passing the array (by value) is to pass its address to the function, so that it can manipulate it through a pointer.
However, returning by value an array's address isn't possible, since by the time control reaches the caller, the function goes out of scope and its automatic variables go down with it too. Hence if you really have to, you can dynamically allocate the array, populate and return it, but the preferred method is passing the array and leaving the onus of maintaining the array to the caller.
As for the error, the only warning I get in GCC for this is warning: 'return' with a value, in function returning void which is simply meaning that you shouldn't return anything from a void function.
void new_array (int x[n][n]); what you're really doing here is taking a pointer to an array of n integers; the decayed type is int (*x)[n]. This happens because arrays decay into pointers generally. If you know n at compile time, perhaps the best way to pass is:
#define n 3
void new_array (int (*x)[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
}
And call it as
int arr[n][n];
new_array(&arr);
You can pass around arbitrarily dimensions arrays like any another variable if you wrap them up in a struct:
#include <stdio.h>
#define n 3
struct S {
int a[n][n];
};
static struct S make_s(void)
{
struct S s;
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
s.a[i][j] = i + j;
}
return s;
}
static void print_s(struct S s)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
printf(" %d", s.a[i][j]);
printf("\n");
}
}
int main(void) {
struct S s;
s = make_s();
print_s(s);
return 0;
}
You are probably declaring n as a constant integer:
const int n = 3;
Instead, you should define n as a preprocessor definition:
#define n 3

Pass an array to a function by value

Below is a snippet from the book C Programming Just the FAQs. Isn't this wrong as Arrays can never be passed by value?
VIII.6: How can you pass an array to a function by value?
Answer: An array can be passed to a function by value by declaring in
the called function the array name
with square brackets ([ and ])
attached to the end. When calling the
function, simply pass the address of
the array (that is, the array’s name)
to the called function. For instance,
the following program passes the array
x[] to the function named
byval_func() by value:
The int[] parameter tells the
compiler that the byval_func()
function will take one argument—an
array of integers. When the
byval_func() function is called, you
pass the address of the array to
byval_func():
byval_func(x);
Because the array is being passed by
value, an exact copy of the array is
made and placed on the stack. The
called function then receives this
copy of the array and can print it.
Because the array passed to
byval_func() is a copy of the
original array, modifying the array
within the byval_func() function has
no effect on the original array.
Because the array is being passed by value, an exact copy of the array is made and placed on the stack.
This is incorrect: the array itself is not being copied, only a copy of the pointer to its address is passed to the callee (placed on the stack). (Regardless of whether you declare the parameter as int[] or int*, it decays into a pointer.) This allows you to modify the contents of the array from within the called function. Thus, this
Because the array passed to byval_func() is a copy of the original array, modifying the array within the byval_func() function has no effect on the original array.
is plain wrong (kudos to #Jonathan Leffler for his comment below). However, reassigning the pointer inside the function will not change the pointer to the original array outside the function.
Burn that book. If you want a real C FAQ that wasn't written by a beginner programmer, use this one: http://c-faq.com/aryptr/index.html.
Syntax-wise, strictly speaking you cannot pass an array by value in C.
void func (int* x); /* this is a pointer */
void func (int x[]); /* this is a pointer */
void func (int x[10]); /* this is a pointer */
However, for the record there is a dirty trick in C that does allow you to pass an array by value in C. Don't try this at home! Because despite this trick, there is still never a reason to pass an array by value.
typedef struct
{
int my_array[10];
} Array_by_val;
void func (Array_by_val x);
Isn't this wrong as arrays can never be passed by value?
Exactly. You cannot pass an array by value in C.
I took a look at the quoted part of the book and the source of this confusion or mistake is pretty fast found.
The author did not know about that *i is equivalent to i[] when provided as a parameter to a function. The latter form was invented to explicitly illustrate the reader of the code, that i points to an array, which is a great source of confusion, as well-shown by this question.
What I think is funny, that the author of the particular part of the book or at least one of the other parts (because the book has 5 authors in total) or one of the 7 proofreaders did not mentioned at least the sentence:
"When the byval_func() function is called, you pass the address of the array to byval_func():"
With at least that, they should had noticed that there is a conflict.
Since you passing an address, it is only an address. There is nothing magically happen which turns an address into a whole new array.
But back to the question itself:
You can not pass an array as it is by value in C, as you already seem to know yourself. But you can do three (there might be more, but that is my acutal status of it) things, which might be an alternative depending on the unique case, so let´s start.
Encapsulate an array in a structure (as mentioned by other answers):
#include <stdio.h>
struct a_s {
int a[20];
};
void foo (struct a_s a)
{
size_t length = sizeof a.a / sizeof *a.a;
for(size_t i = 0; i < length; i++)
{
printf("%d\n",a.a[i]);
}
}
int main()
{
struct a_s array;
size_t length = sizeof array.a / sizeof *array.a;
for(size_t i = 0; i < length; i++)
{
array.a[i] = 15;
}
foo(array);
}
Pass by pointer but also add a parameter for determine the size of the array. In the called function there is made a new array with that size information and assigned with the values from the array in the caller:
#include <stdio.h>
void foo (int *array, size_t length)
{
int b[length];
for(size_t i = 0; i < length; i++)
{
b[i] = array[i];
printf("%d\n",b[i]);
}
}
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
foo(a,(sizeof a / sizeof *a));
}
Avoid to define local arrays and just use one array with global scope:
#include <stdio.h>
int a[10];
size_t length = sizeof a / sizeof *a;
void foo (void)
{
for(size_t i = 0; i < length; i++)
{
printf("%d\n",a[i]);
}
}
int main()
{
for(size_t i = 0; i < length; i++)
{
a[i] = 25;
}
foo();
}
In C and C++ it is NOT possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address. In practice this has almost the same effect and it is a much faster and more efficient operation.
To be safe, you can pass the array size or put const qualifier before the pointer to make sure the callee won't change it.
Yuo can work it around by wrapping the array into the struct
#include <stdint.h>
#include <stdio.h>
struct wrap
{
int x[1000];
};
struct wrap foo(struct wrap x)
{
struct wrap y;
for(int index = 0; index < 1000; index ++)
y.x[index] = x.x[index] * x.x[index];
return y;
}
int main ()
{
struct wrap y;
for(int index = 0; index < 1000; index ++)
y.x[index] = rand();
y = foo(y);
for(int index = 0; index < 1000; index ++)
{
printf("%d %s", y.x[index], !(index % 30) ? "\n" : "");
}
}
#include<stdio.h>
void fun(int a[],int n);
int main()
{
int a[5]={1,2,3,4,5};
fun(a,5);
}
void fun(int a[],int n)
{
int i;
for(i=0;i<=n-1;i++)
printf("value=%d\n",a[i]);
}
By this method we can pass the array by value, but actually the array is accessing through the its base address which actually copying in the stack.

Resources