I am writing a code to processing a 2-d char array.
char *board[] = {"aa"};
I pass the array to a function
search(board, row, col);
..........
bool search(char** boards, int row, int col)
{
// Inside the function, I want to modify the boards[x][y]
// from the board within x and y, x < row, y < col
// I get the segmentation fault here because the boards is
// allocated to the static memory and cannot be changed.
boards[x][y] = 'c';
}
In C++, I can use
vector< vector<char> boards
to change the elements in the specific location.
But in C, there is no vector.
Is anyone has good advice about how to modify the boards 2-D array?
Thanks.
The problem is that you are making an array of pointers, and set the pointers to ppint to string constants. Memory of string constants is not modifiable, so writing to it causes segmentation fault.
Changing an array of pointers to 2D array of characters will fix this problem
char board[][10] = {"aa", "bb"};
In C you can use for example Variable Length Arrays if the compiler supports them.
For example
int size_t m = 2;
int size_t n = 3;
char board[m][n] = { "aa", "bb" };
search( m, n, board );
// Add more search code here...
bool search( size_t rows, size_t cols, char board[][cols] );
Another approach is to use an arrays of pointers where each pointer points to a dynamically allocated array or the array itself can be dynamically allocated. For example
int size_t m = 2;
int size_t n = 3;
char **board;
board = malloc( m * sizeof( char * ) );
for ( size_t i = 0; i < m; i++ ) board[i] = malloc( n * sizeof( char ) );
strcpy( board[0], "aa" );
strcpy( board[1], "bb" );
search( board, m, n );
//,,,
bool search( char **board, size_t rows, size_t cols );
In this case you have to free the allocated memory when array will not be needed any more.
As for the segmentation fault you got then you are trying to change a string literal. They are immutable. Any attempt to modify a string literal results in undefined behaviour.
Try declaring board as 2D array,
char board[10][10]
Also change the search function declaration to use board as a 2D array like:
Search(char board[][], int x, int y) {...
I think that your code is fails because you mix arrays of pointers with an argument which expect a pointer pointer to char.
Regards
Related
I was trying to swap two arrays using pointers.
What I wanted was to swap using a call by reference.
This code I wrote is given below
#include <stdio.h>
#include <stdlib.h>
void swap(int **a, int **b) {
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = {6, 7, 8, 9, 10};
swap((int**)&arr1, (int**)&arr2);
for(int i=0; i<5; i++) printf("%d\t", arr1[i]);
printf("\n");
for(int i=0; i<5; i++) printf("%d\t", arr2[i]);
printf("\n");
}
The output of the code is:
6 7 3 4 5
1 2 8 9 10
instead of:
6 7 8 9 10
1 2 3 4 5
What did I do wrong?
In this call
swap((int**)&arr1, (int**)&arr2);
the passed pointers point to first elements of the arrays arr1 and arr2.
So within the function swap
void swap(int **a, int **b) {
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
*a = *b;
*b = temp;
}
dereferencing the pointers like for example
*a
results in reading the first two elements of the array arr1 as a pointer because in your system sizeof( int * ) is equal to 2 * sizeof( int ).
That is values of first two elements of the arrays are interpreted as values of pointers.
And the obtained output confirms that
6 7 3 4 5
1 2 8 9 10
^^^^^
Moreover the function has a memory leak because at first memory was allocated dynamically and its address was assigned to the pointer temp and then the pointer was reassigned
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
So the address of the allocated memory was lost and the memory was not freed.
You can not swap arrays such a way. You need to swap each pair of elements of the arrays.
The function can look for example the following way
void swap( int *a, int *b, size_t n )
{
for ( int *p = a; p != a + n; ++p, ++b )
{
int temp = *p;
*p = *b;
*b = temp;
}
}
And the function is called like
swap( arr1, arr2, 5 );
A less flexible function can look the following way
void swap( int ( *a )[5], int ( *b )[5] )
{
for ( int *p1 = *a, *p2 = *b; p1 != *a + 5; ++p1, ++p2 )
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
}
And the function is called like
swap( &arr1, &arr2 );
First of all lets fix your swap function:
void swap(int **pparr1, int **pparr2)
{
int *temp = *pparr1;
*pparr1 = *pparr2;
*pparr2 = temp;
}
This function now swaps the two pointers that parr1 and parr2 are pointing to.
Then lest update the way to call this function:
int *parr1 = arr1; // Make parr1 point to the first element of arr1
int *parr2 = arr2; // Make parr2 point to the first element of arr2
// Swap the two pointers
swap(&parr1, &parr2);
And then we print using the pointers instead of the arrays:
printf("arr1 = [ ");
for (unsigned i = 0; i < 5; ++i)
{
printf("%d ", parr1[i]);
}
printf("]\n");
printf("arr2 = [ ");
for (unsigned i = 0; i < 5; ++i)
{
printf("%d ", parr2[i]);
}
printf("]\n");
This will print the arrays as if they were swapped, but in fact the arrays themselves are not swapped. You can verify by printing using the arrays arr1 and arr2 themselves.
If you want to swap the actual contents of the arrays, you need a loop to actually swap the elements themselves:
// Function to swap two integer values
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
// Function to swap two arrays
void swap_arrays(int *pa1, int *pa2, size_t size)
{
for (size_t i = 0; i < size; ++i)
{
// Swap each separate element of the arrays
swap(&pa1[i], &pa2[i]);
}
}
Call like
swap_arrays(arr1, arr2, 5);
After this the contents of the arrays themselves have been swapped.
swap((int**)&arr1, (int**)&arr2);
It looks like your idea is to have swap swap the address of arr1 with the address of arr2. Variables in C, including arrays, do not work this way, and this idea cannot possibly work.
arr1 is a name for the array. It is not the address of the array, nor is it a variable whose value is the address of the array. There is no pointer to the array that can be swapped with a pointer to the array arr2.
When the compiler processes int arr1[] = {1, 2, 3, 4, 5};, it creates an array of five int, and then it uses arr1 to refer to that array. Wherever arr1 is used, the compiler creates code that will refer to the array. It does not do this by storing the address of the array in some memory location you can swap with another address. It has ways to access the array using registers and processor instructions set up for that.
In swap((int**)&arr1, (int**)&arr2);, you take the addresses of arr1 and arr2 and convert them to int **. The address of arr1 is the address where its contents are. What is at that address in memory is the int elements, not a pointer. So the int ** type does not make sense for this; the address of arr1 is not the address of an int *.
The reason you get the output you do is that int objects are four bytes in your C implementation and int * objects are eight bytes. So when temp = *a; attempts to get the int * that a should be pointing to, it gets the first eight bytes in arr1. Then *a = *b; replaces those eight bytes with the first eight bytes in arr2. And *b = temp; replaces the first eight bytes in arr2 with the saved eight bytes from arr1.
Note that, in these three statements, temp is used to hold eight bytes from arr1. The value it was given in int *temp = (int*)malloc(5*sizeof(int)); is lost when temp is assigned another value in temp = *a;.
Also note that this behavior you observed in this instance is not specified by the C standard, and different behavior can result in other circumstances, including alignment errors and surprising transformations of the program by compiler optimization.
You cannot assign whole arrays to each other in a single operation using =; you must either use a library function like memcpy or assign each element individually.
Under most circumstances, expressions of type "N-element array of T" will be converted, or "decay", to expressions of type "pointer to T" and the value will be a pointer to the first element. If you called the function as
swap( arr1, arr2 );
it would be equivalent to writing
swap( &arr1[0], &arr2[0] );
So you're already passing the arrays "by reference", just not in the way you're probably thinking.
The easiest way to do what you want would be something like this:
void swap( int *a, int *b, size_t count )
{
for ( size_t i = 0; i < count; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
Alternately, you could use memcpy with a temporary array:
void swap( int *a, int *b, size_t count )
{
int tmp[count]; // C99 or later
memcpy( tmp, a, count );
memcpy( a, b, count );
memcpy( b, tmp, count );
}
In this case tmp is a variable-length array, whose size is provided by a runtime value. VLAs are useful for things like this if the array size isn't too big, but they're only available for C99 and later, and are optional after C2011. If your arrays are very large or VLAs aren't available, then this would be a case for dynamic memory:
void swap( int *a, int *b, size_t count )
{
int *tmp = calloc( count, sizeof *tmp );
if ( tmp )
{
memcpy( tmp, a, count );
memcpy( a, b, count );
memcpy( b, tmp, count );
free( tmp );
}
}
The first method (swapping each element individually) would be my preference. It avoids any kind of dynamic memory management, it's straightforward, it's not making a bunch of library calls, etc.
In all three cases, you'd call it as
swap( arr1, arr2, 5 );
Beware explicit casts, especially pointer casts - they're usually a sign you're doing something wrong.
In the bellow example, I would like to change some of the characters of my 2D array using standard "array[x][y]" syntax, I have tried several syntax such has *(world[0][1]), ... but always getting error Syntax or segmentation fault.
char *map[] = { "12345\0",
"67890\0"
};
void change( char **world) {
world[0][1] = 'X'; // <-- I want to replace character 2 of line 1 (2) by char 'X'
}
void main() {
printf("line=%s\n",map[0]);
printf("char=%c\n",map[0][1]);
change(map);
printf("now line is =%s\n",map[0]);
}
resulting
$ ./a.out
line=12345
line=2
Segmentation fault
Thanks for your help
The Problem
you can't use arr[y][x] syntax, because
void foo(char **bar) {
(char[H][W)bar; // ILLEGAL
}
is illegal, you can't turn a char ** into a char [][], you either have to use a different syntax or pass map not as a pointer, but as an array(and change the type of map)
SOLUTIONS
What you can do is take map as a char [][]
// note that you have to change from char *map[] to this
char map[H][W] = ...;
map[y][x] = '9';
OR
With a pointer to a multi-dimentional, you can get the element at n, with something like:
#define W 5 // width
#define H 2 // height
char *arr[H][W] = { "1234\0", "5678\0" };
// start is &arr[0][0]
void changeAt(char *start, int n, char x) {
// treat arr as a 1 dimentional array
*(start + (n / W) + (n % W)) = x;
}
// start is &arr[0][0]
void changeXY(char *start, int x, int y, char n) {
*(start + (y / W) + x) = n;
}
In C language, 2D arrays and arrays of pointers are different animals.
char *map[] = { "12345\0",
"67890\0"
};
declares an array of 2 char pointers, both pointing to non modifiable string literals.
You can initialize non const char arrays from a literal and then use them in your array of pointers:
char arr1[] = "12345\0"; // 7 chars with 2 terminating null characters
char arr2[] = "64789\0"; // id.
char *map[] = {arr1, arr2};
Alternatively, you can declare a true 2D array (all rows have same size) and initialize it:
char map[][7] = {"12345", "6789"};
I just learned about variable length arrays in C, and somebody suggested to me that I can realize a 3D array-like object in C simply as a pointer to a variable length array. A simple implementation would look as follows:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] ) {
size_t ii, jj, kk,
Nx, Ny, Nz;
Nx = 2;
Ny = 3;
Nz = 4;
// initialize 3D array as pointer to a variable length array
double (*arr3d)[Ny][Nz] = calloc(Nx, sizeof *arr3d);
for( ii=0 ; ii<Nx ; ++ii )
for( jj=0 ; jj<Ny ; ++jj )
for( kk=0 ; kk<Nz ; ++kk )
printf( "arr3d[%ld,%ld,%ld] = %f, address = %p\n",
ii, jj, kk, arr3d[ii][jj][kk], &arr3d[ii][jj][kk] );
free(arr3d);
return 0;
}
In my understanding, one advantage (besides of the one-line implementation) is that arr3d can be simply passed to a function,
int doSomething( size_t dim1, size_t dim2, size_t dim3, double arr3d[dim1][dim2][dim3] );
by calling this function in the main function as follows:
doSomething( Nx, Ny, Nz, arr3d );
My question now, is this a valid implementation of a 3D array-like object or will I run into some trouble ? Note that in the actual case, the dimensions are larger by roughly a factor of 1000 each.
If you have an array like
double a[Nx][Ny][Nz];
then you may write
double (*arr3d)[Ny][Nz] = a;
that is the pointer arr3d points to the first element of the array a that has the type double{Nt][Nz].
So this memory allocation
double (*arr3d)[Ny][Nz] = calloc(Nx, sizeof *arr3d);
is correct. There is in fact allocated dynamically a thre-dimensional array and the pointer arr3d points to the first element of the array.
I have problem understanding the code below.
What value index=strlen(strs[0]) gets?
char *a= malloc (sizeof(char)*(index+1)) Is this the standard way to allocate array for char array?
What does strs[i][j] represent?
This is the code I found on leetcode. Just trying to understand the code. (code from sanghi user on leetcode)
#include<string.h>
char* longestCommonPrefix(char** strs, int strsSize)
{
int i=0; int j=0;int index;int tempindex=0;
if(strsSize<1)
return "";
index=strlen(strs[0]);
char *a;
a= malloc(sizeof(char)*(index+1));
strcpy(a,strs[0]);
for(i=1;i<strsSize;i++)
{ tempindex=0;
for(j=0;j<index;j++)
{
if(a[j]==strs[i][j])
tempindex++;
else
{a[j]='\0';
break;
}
}
if (tempindex==0)return ("");
if(tempindex<index)index=tempindex;
}
return a;
}
Expected results can be found on https://leetcode.com/problems/longest-common-prefix/
strs is an array of strings. strsSize is the number of strings in the array.
index = strlen(strs[0]);
This simply gets the length of strs[0], the first string in the array.
a = malloc(sizeof(char)*index+1);
This will allocate enough memory to store a string of the same size. I say enough memory because each string actually has length + 1 characters. The last character is \0, a null terminator. You always have to make sure to terminate your strings or else a bunch of weird buffer overflow stuff can happen.
str[i][j]
This accesses the jth character in the ith string in the array.
For starters the program is bad and invalid.:)
For example the size of the one dimensional array first element of which is pointed to by the parameter strs shall have the type size_t instead of int.
And all other variables that deal with indices also shall have the type size_t as for example
size_t index = strlen( strs[0] );
because the standard C function strlen has the return type size_t.
The source array is not changed in the function so the first parameter shall be declared with the qualifier const.
That is the function declaration shall look like
char * longestCommonPrefix( const char** strs, size_t strsSize);
Farther the elements (strings) of the array can have different lengths, So this loop
for(j=0;j<index;j++)
has undefined behavior because some element (string) of the array can have length less than the value of the variable index.
In fact there is no need to calculate lengths of the elements of the array. The loop can use the condition
for( j=0; j < index && strs[i][j] != '\0'; j++)
And moreover the function has a memory leak due to this return sub-statement in the if statement
a= malloc(sizeof(char)*(index+1));
//...
if (tempindex==0)return ("");
That is the allocated memory pointed to by the pointer a will not released.
What value index=strlen(strs[0]) gets?
index gets the length of the string stored in the first element of the array of strings.
For example if you have an array
char *strs[] = { "Hello", "Bye", "Good Morning" };
then index is set to the length of the string "Hello".
char a= malloc (sizeof(char)(index+1)) Is this the standard way to
allocate array for char array?
Yes in this declaration there is allocated a memory large enough to store the string (including its terminating zero) of the first element of the array pointed to by strs.
What does strs[i][j] represent?
strs[i][j] access j-th character of the i-th element of the array pointed to by strs.
For example for the declaration above strs[0][0] is equal to 'H', strs[0][1] is equal to 'e', strs[1][0] is equal to 'B' and so on.
P.S. A better approach to define the function is the following as it is shown in the demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t longestCommonPrefix( const char **strs, size_t strsSize )
{
size_t n = 0;
if ( strsSize != 0 )
{
n = strlen( *strs );
for ( size_t i = 1; n != 0 && i < strsSize; i++ )
{
size_t j = 0;
while ( j < n && strs[i][j] == strs[i-1][j] ) j++;
if ( j < n ) n = j;
}
}
return n;
}
int main(void)
{
char * strs[] = { "0123456789", "012345", "0123" };
size_t n = longestCommonPrefix( ( const char ** )strs, sizeof( strs ) / sizeof( *strs ) );
char *p = NULL;
if ( n != 0 )
{
p = malloc( n + 1 );
memcpy( p, strs[0], n );
p[n] = '\0';
printf( "The longest common prefix is \"%s\"\n", p );
}
free( p );
return 0;
}
The program output is
The longest common prefix is "0123"
In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?
Besides, my multidimensional array may contain types other than strings.
Pass an explicit pointer to the first element with the array dimensions as separate parameters. For example, to handle arbitrarily sized 2-d arrays of int:
void func_2d(int *p, size_t M, size_t N)
{
size_t i, j;
...
p[i*N+j] = ...;
}
which would be called as
...
int arr1[10][20];
int arr2[5][80];
...
func_2d(&arr1[0][0], 10, 20);
func_2d(&arr2[0][0], 5, 80);
Same principle applies for higher-dimension arrays:
func_3d(int *p, size_t X, size_t Y, size_t Z)
{
size_t i, j, k;
...
p[i*Y*Z+j*Z+k] = ...;
...
}
...
arr2[10][20][30];
...
func_3d(&arr[0][0][0], 10, 20, 30);
You can declare your function as:
f(int size, int data[][size]) {...}
The compiler will then do all pointer arithmetic for you.
Note that the dimensions sizes must appear before the array itself.
GNU C allows for argument declaration forwarding (in case you really need to pass dimensions after the array):
f(int size; int data[][size], int size) {...}
The first dimension, although you can pass as argument too, is useless for the C compiler (even for sizeof operator, when applied over array passed as argument will always treat is as a pointer to first element).
You can do this with any data type. Simply make it a pointer-to-pointer:
typedef struct {
int myint;
char* mystring;
} data;
data** array;
But don't forget you still have to malloc the variable, and it does get a bit complex:
//initialize
int x,y,w,h;
w = 10; //width of array
h = 20; //height of array
//malloc the 'y' dimension
array = malloc(sizeof(data*) * h);
//iterate over 'y' dimension
for(y=0;y<h;y++){
//malloc the 'x' dimension
array[y] = malloc(sizeof(data) * w);
//iterate over the 'x' dimension
for(x=0;x<w;x++){
//malloc the string in the data structure
array[y][x].mystring = malloc(50); //50 chars
//initialize
array[y][x].myint = 6;
strcpy(array[y][x].mystring, "w00t");
}
}
The code to deallocate the structure looks similar - don't forget to call free() on everything you malloced! (Also, in robust applications you should check the return of malloc().)
Now let's say you want to pass this to a function. You can still use the double pointer, because you probably want to do manipulations on the data structure, not the pointer to pointers of data structures:
int whatsMyInt(data** arrayPtr, int x, int y){
return arrayPtr[y][x].myint;
}
Call this function with:
printf("My int is %d.\n", whatsMyInt(array, 2, 4));
Output:
My int is 6.
In C can I pass a multidimensional array to a function as a single argument when I don't know what the dimensions of the array are going to be?
No
If by "single argument" you mean passing just the array without passing the array dimensions, no you can't. At least not for true multidimensional arrays.
You can put the dimension[s] into a structure along with the array and claim you're passing a "single argument", but that's really just packing multiple values into a single container and calling that container "one argument".
You can pass an array of known type and number of dimensions but unknown size by passing the dimensions themselves and the array like this:
void print2dIntArray( size_t x, size_t y, int array[ x ][ y ] )
{
for ( size_t ii = 0, ii < x; ii++ )
{
char *sep = "";
for ( size_t jj = 0; jj < y; jj++ )
{
printf( "%s%d", sep, array[ ii ][ jj ] );
sep = ", ";
}
printf( "\n" );
}
}
You would call that function like this:
int a[ 4 ][ 5 ];
int b[ 255 ][ 16 ];
...
print2dIntArray( 4, 5, a );
....
printt2dIntArray( 255, 16, b );
Similarly, a 3-dimensional array of, for example, a struct pixel:
void print3dPixelArray( size_t x, size_t y, size_t z, struct pixel pixelArray[ x ][ y ][ z ] )
{
...
}
or a 1-dimensional double array:
void print1dDoubleArray( size_t x, double doubleArray[ x ] )
{
...
}
BUT...
However, it can be possible to pass "arrays of pointers to arrays of pointers to ... an array of type X" constructs that are often mislabeled as a "multidimensional array" as a single argument as long as the base type X has an sentinel value that can be used to indicate the end of the final, lowest-level single-dimensional array of type X.
For example, the char **argv value passed to main() is a pointer to an array of pointers to char. The initial array of char * pointers ends with a NULL sentinel value, while each char array referenced by the array of char * pointers ends with a NUL character value of '\0'.
For example, if you can use NAN as a sentinel value because actual data won't ever be a NAN, you could print a double ** like this:
void printDoubles( double **notAnArray )
{
while ( *notAnArray )
{
char *sep = "";
for ( size_t ii = 0; ( *notAnArray )[ ii ] != NAN; ii++ )
{
printf( "%s%f", sep, ( *notAnArray )[ ii ] );
sep = ", ";
}
notAnArray++;
}
}
int matmax(int **p, int dim) // p- matrix , dim- dimension of the matrix
{
return p[0][0];
}
int main()
{
int *u[5]; // will be a 5x5 matrix
for(int i = 0; i < 5; i++)
u[i] = new int[5];
u[0][0] = 1; // initialize u[0][0] - not mandatory
// put data in u[][]
printf("%d", matmax(u, 0)); //call to function
getche(); // just to see the result
}