I'm trying to pass the address of a 2D array to a function in C. I initialize the 2D array as:
const int N = 3;
char t[N][N];
I try to convert this into a char***:
char*** t_ptr = &t;
But it fails with a:
warning: initialization from incompatible pointer type
The function I want to receive the array has a prototype such as:
void f(char*** t, int N) { ... };
What am I doing wrong? Thank you.
This
char*** t_ptr = &t;
is wrong as compiler pointed because t is an two dimensional array, instead of triple pointer like char*** use pointer to an array to point to it. For e.g
char t[3][3] = { "ab","de","gh"}; /* total 3 1D array & each 1D array has 3 elements */
char (*t_ptr)[3] = t; /* t_ptr is a pointer to an array, pointing to 3 elements at a time */
And you can print t_ptr like
for(int index = 0; index < 3 ; index++) {
printf("%s\n",t_ptr[index]);
}
For reading c declarations, you can visit: https://cdecl.org/
Now using #Achal's example array:
#include <stdio.h>
#include <stdlib.h>
int main()
{
// t is a 2D array (not a VLA)
char t[3][3] =
{
{'a', 'b', '\0'},
{'d', 'e', '\0'},
{'g', 'h', '\0'}
};
printf("t is composed of 3 arrays of 3 characters each,\n");
printf("with the following addresses (on my machine):\n");
printf("--------------------------------------------------\n");
printf("%p, %p, %p\n", t[0], t[1], t[2]);
// ------------------------------------------------
// p is an array of 3 char pointers or char*
// Notice initialization
char* p[3] = {t[0], t[1], t[2]};
// following line of code will break, if no '\0' is encountered
// since %s requires a char* and a null terminator
printf("\nPrint strings using p:\n");
printf("------------------------\n");
printf("%s, %s, %s\n", *p, *(p + 1), *(p + 2));
// ------------------------------------------------
// q is a pointer to a char* or q has type char**
// Notice initialization of q (q points to p)
char** q = p;
printf("\nUsing q:\n");
printf("-----------\n");
printf("%s, %s, %s\n", *q, *(q + 1), *(q + 2));
// ---------------- printing characters individually
printf("\nIndividually:\n");
printf("---------------\n");
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
printf("%c ",
*(*(q + i) + j)
);
}
printf("\n");
}
// -----------------------------------------------
// r is a pointer to an array of size 3 containing char
// r advances three char at a time (r doesn't know the size of t)
char (*r)[3] = t; // this is the type of t
printf("\nUsing r:\n");
printf("---------------\n");
printf("%p, %p, %p\n", *r, *(r + 1), *(r + 2));
// to extract chars
printf("%c, %c", *(*(r + 0) + 0), *(*(r + 2) + 1));
// -----------------------------------------------
return EXIT_SUCCESS;
}
Output:
t is composed of 3 arrays of 3 characters each,
with the following addresses (on my machine):
--------------------------------------------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
Print strings using p:
------------------------
ab, de, gh
Using q:
-----------
ab, de, gh
Individually:
---------------
a b
d e
Using r:
---------------
000000000022FE2F, 000000000022FE32, 000000000022FE35
a, h
Process returned 0 (0x0) execution time : -0.000 s
Press any key to continue.
char t[N][N];
is in fact the same as
char t[N * N];
in memory. A pointer to such an array would in both cases be of type char *.
char *** is a pointer to a pointer, that is a pointer to a char, whereas char * is a pointer to a char and that's how you pass array references in C: You pass them as a pointer to the first element of that array and this first element is a char.
C cannot retain the exact type or structure of an array as soon as you pass it to functions. In memory, a char array is just a bunch of memory filled with chars and all you can pass around is a pointer to that memory. If that memory is char [] or char [][] or even char [][][] plays no role, in memory all three are a block full of chars and the function would have to explicitly know the structure in memory, otherwise all char arrays will always be char [] for a function.
I strongly discourage C beginners to ever use multidimensional arrays. Instead of
char t[N][N];
char c = t[y1][x1];
t[y2][x2] = 'X';
use
char t[N];
char c = t[y1 * N + x1];
t[y2 * N + x2] = 'X';
As that's basically what the compiler will internally do anyway.
Note that multidimensional arrays in C are not x-y, but y-x, the first value is the row, the second on the column, please see this tutorial.
Whoever disbelieves what I just said, try out this code:
int main ( ) {
char a[5][5];
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
a[y][x] = x + 10 * y;
}
}
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%02d ", a[y][x]);
}
printf("\n");
}
printf("------\n");
char * a2 = (char *)a;
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
printf("%02d ", a2[y * 5 + x]);
}
printf("\n");
}
}
You can run it online, if you like, the output is identical. Also have a look at the assembly code the compiler generates for either loop (e.g. gcc -S) and you will see it's almost identical as even in the first case the compiler uses an add and a mul instruction to access the correct memory location within the array.
Related
I am trying to print a 2-D array in C by using pointers but I am not getting the expected output.
Program:-
#include <stdio.h>
int main()
{
int arr[2][3] = {{1,2,3},{4,5,6}};
int* p;
for ( p = arr; p <= arr+6; p++)
{
printf("%d ", *p);
}
return 0;
}
Output:-
1 2 3 4 5 6 -1116112128 1587637938 0 0 1893963109 32521 -1453950296 32766 -1453805568 1 800797033 21984 -1453949463
Could you tell me where I am wrong as the output should only be:
1 2 3 4 5 6
Could you tell me where I am wrong
The elements of arr are not integers, but arrays of 3 integers. So arr+6 is surely a different address than what you expect, since pointer arithmetic works in multiples of the size of the type in the array.
You'll always be better off using nested loops to iterate over a multidimensional array; treating it as one single-dimensional array of int leads to exactly the kinds of confusion you see here. The code is harder to understand and verify, it won't be any slower.
First, when looping through arrays of size n wth an index i, the condition for continuation should be i < n rather than i <= n, because array indexes in C run from 0 through n-1.
However, your code has a more serious error: 1-dimensional arrays can be 'decayed' into pointers to the elements' type; however, 2-dimensional arrays decay into pointers to 1-dimensional arrays. So, in your case, the type of the pointer used in the arr + 6 expression is a pointer to an array of three integers; further, when the 6 is added, that operation is performed in terms of the size of the pointed-to object, which is sizeof(int) * 3 – so, even when changing the <= to <, you will be running far beyond the actual bounds of the array.
To make the pointer arithmetic work in the correct 'units' (i.e. sizeof(int)), cast the arr to an int* before the addition (and also change the <= to <):
#include <stdio.h>
int main()
{
int arr[2][3] = { {1,2,3},{4,5,6} };
int* p;
for (p = (int*)arr; p < (int*)arr + 6; p++) {
printf("%d ", *p);
}
return 0;
}
You are trying to access the value in the wrong way, The two-dimensional array is saved as a continuous block in the memory. So, if we increment the value of ptr by 1 we will move to the next block in the allocated memory.
int arr[2][3] = {{1,2,3},{4,5,6}};
int *ptr = arr;
int i,j;
for (i = 0; i < 6; i++) {
printf("%d ", *(ptr + i));
}
return 0;
Array designators used in expressions with rare exceptions are implicitly converted to pointers to their first elements.
The type of the array elements of this array
int arr[2][3];
is int [3]. So a pointer to the first element of the array has the type int ( * )[3].
This assignment
p = arr;
where p has the type int * is incorrect because the operands of the assignment have incompatible pointer types.
At least you need to cast the right expression to the type int * like
p = ( int * )arr;
The same casting you need to use in the condition in the for loop. That is instead of
p <= arr+6
you have to write
p < ( int * )arr+6
Below there is a demonstration program that shows how to output a two-dimensional array as a two-dimensional array using pointers.
#include <stdio.h>
int main( void )
{
int arr[2][3] = {{1,2,3},{4,5,6}};
for ( int ( *p )[3] = arr; p != arr + 2; p++ )
{
for ( int *q = *p; q != *p + 3; ++q )
{
printf( "%d ", *q );
}
putchar( '\n' );
}
return 0;
}
If you want to output the two-dimensional array as a one-dimensional array then you can write
#include <stdio.h>
int main( void )
{
int arr[2][3] = {{1,2,3},{4,5,6}};
for ( int *p = ( int * )arr; p != ( int * )arr + 6; p++ )
{
printf( "%d ", *p );
}
putchar( '\n' );
return 0;
}
In
for ( p = arr; p <= arr+6; p++)
the expression arr, as an rvalue, is a pointer to the first element of the array (which is of type int [3], so each time you increment that pointer, it moves three int positions forward ---a whole row---, and so, arr + 6 points just after the sixth row of the array (if the array should ever had six rows) You can do it (with the proper explicit pointer conversions, as you are mixing pointers to int with pointers to int [3]) with the expression arr + 2 which is the addres of the first array element after the second row (and the number of rows of the array).
You can do it also declaring
int (*aux)[2][3] = &arr; /* aux is a pointer to the whole 3x2 array,
* so aux + 1 will be the position of the second
* 2D array after this one */
and then
int *end = (int *)(aux + 1);
or simply
int *end = (int *)(&arr + 1); /* see below */
(Beware that arr and &arr are both pointers and point to the same place, but they are not the same type (arr is of type int (*)[3] and &arr is of type int(*)[2][3])
So let's rewrite your code as
for (p = (int *)arr; p < end; p++)
or
for (p = (int *)arr; p < (int *)&arr + 1; p++)
would work, which seems more natural to do the calculus in complete array units than in rows or single cells (and you can change freely the dimensions of the array)
Your code would be:
#include <stdio.h>
int main()
{
int arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
int *end = (int *)(&arr + 1); /* try to avoid evaluating this expression in the loop
* despite that it can be optimized to comparing
* with a constant value */
char *sep = "";
for (int *p = (int *)arr; p < end; p++)
{
printf("%s%d", sep, *p);
sep = ", ";
}
putchar('\n');
return 0;
}
(Beware that you have to use < operator and not <= as you don't want to print the value pointed by end, because it lies one place outside of the array)
Finally a note: this will work with true arrays, but not with function parameters declared as arrays, because they decay to pointers and then &arr is not a pointer to data the size of the array, but it is the address of the parameter itself, which points to the array somewhere else.
First function changes big letter to small. In main I need to have five strings and with function konvertuj I have to go through that array and check for each letter if it's big and convert it to small. The point is that I don't know how to access each character of string in the function. (It's study example so it has to be done with these predefined functions.
char v2m(char z){
char m = z + 0x20;
return m;
}
void konvertuj(char **niz, int n){
for (int i = 0; i < n; i++)
if(*niz[i] > 'A' && *niz[i] < 'Z')
*niz[i] = v2m(*niz[i]);
}
int main(){
char **niz;
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
for (int i = 0; i < 5; i++)
{
int d = -1;
while(niz[i][++d]);
konvertuj(&niz[i], d);
printf("%s ", niz[i]);
}
}
v2m - no need of the variable m
konvertuj no need to iterate through the same letters all over again. You want to convert 1 letter as you iterate in main. Your condition is wrong as you will ignore 'A' and 'Z'
Pointer to pointer does not have allocated space to accommodate 5 pointers. You need to allocate this space. In your code is it UB.
3.a You assign the pointers to the string literals. Attempt to modify the string literal invokes Undefined Behaviour. In my code, I use compound literals which are modifiable.
3.b use correct type for indexes (size_t).
char v2m(char z){
return z + 0x20;
}
void konvertuj(char *niz, size_t n){
if(niz[n] >= 'A' && niz[n] <= 'Z')
niz[n] = v2m(niz[n]);
}
int main(void){
char **niz = malloc(5 * sizeof((*niz)));
niz[0] = (char[]){"Voda"};
niz[1] = (char[]){"KraISSa"};
niz[2] = (char[]){"somsssR"};
niz[3] = (char[]){"aaaaa"};
niz[4] = (char[]){"WeWeWeW"};
for (size_t i = 0; i < 5; i++)
{
size_t d = 0;
while(niz[i][d])
konvertuj(niz[i], d++);
printf("%s ", niz[i]);
}
}
As I( understand you need to keep the function names types and parameters
Sure, it is possible to write it the way you did, but you have to build things accordingly and you did not.
And there some errors, anyway. I will try to show you some points. Please be patient.
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
In C in general you can not just assign a value to a string. You use something like
strcpy( niz[0], "ANewValue");
v2m()
Instead of
char v2m(char z){
char m = z + 0x20;
return m;
}
You can just write
char v2m(char z) { return z + 0x20; }
There is no need to declare a char just for holding the return value.
IIUC you can not change the function prototypes...
konvertuj()
void konvertuj(char **niz, int n){
for (int i = 0; i < n; i++)
if(*niz[i] > 'A' && *niz[i] < 'Z')
*niz[i] = v2m(*niz[i]);
}
here I believe you missed the point that the function will receive just a string each time is called, not the whole vector of strings.
The int n is just the length of the string, and even if you could not use strlen() to compute it, it should probably be done inside the function.
but I believe you can not change this prototype also.
note that you are not including 'A' and 'Z' in your test. Maybe you should use '>=' and '<=' in the tests.
since the function gets a single string each call, you must remove many of the '*'
note that you had the strings declared as literals, CONSTANTS that you can not change. The first time you try to change a letter your program will abort
This one below should work and you can compare:
void konvertuj(char *niz, int n)
{
for (int i = 0; i < n; i++)
if(niz[i] >= 'A' && niz[i] <= 'Z')
niz[i] = v2m(niz[i]);
}
main()
Instead of
char **niz;
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
You could write just
char niz[][15] =
{
"Voda",
"KraISSa",
"somsssR",
"aaaaa",
"WeWeWeW"
};
In C just the last dimension must be declared, e.g. the '15' above, since the compiler can determine here the other dimension. And this way you can initialize all of them directly. But in order to change one in the code you need to use a loop and replace letter by letter, or call
strcpy( niz[0], "ANewValue");
Also you can initialize just a few of them, and even out of order, as in
char niz[8][15] =
{
[2] = "somsssR",
[3] = "aaaaa",
[5] = "AomsssZ",
[6] = "A",
[0] = "Voda",
[1] = "KraISSa",
[4] = "WeWeWeW",
[7] = ""
};
and this is really handy.
Computing the number of strings
Note that you can compute the number of strings and even assign "TheLastValue" to the last one, by writing
int n = sizeof(niz)/sizeof(niz[0]); // total of strings
strcpy( niz[n-1], "TheLastValue"); // changes the last string
printf("Total of %llu values\n", sizeof(niz)/sizeof(niz[0]));
What if char** niz is needed?
This is a really common paradigm in C and C++, and it is very useful. You may recall that the prototype for main() is
int main( int argc, char** argc)
for every C program, so you can see how common it is.
Fact is that when you declare niz as char** you are declaring a single variable. What is niz? Well, it is a pointer to a pointer to a char.
niz is char**
*niz is char*
**niz is a single char
But niz is a pointer and it is pointing to nowhere when declared. In your case you want niz pointing to not one but FIVE strings. And if you do nothing the program will abort the first time you try to use it...
You need to build this:
A string is a pointer to the first char, char*
so niz needs to point to an area capable of holding 5 pointers to char
What about the size of a pointer to char? That is easy: sizeof(char*)
Then you need to make each niz[x] point to the required string.
It will not happen by itself. You must build each and every one.
An example: building char** sample from niz as declared above
The code below builds sample as an array of pointers, pointing to the same strings declared and allocated for niz[][] above, and them prints them all
// building an array of pointers to the strings in niz
char** sample = NULL; // ok, points to nothing
unsigned area = n * sizeof(char*); // n pointers to strings
sample = (char**) malloc(area);
for( int i=0; i<n; i+=1)
sample[i] = niz[i];
printf("\n=>\tPrinting the %d strings using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, sample[i]);
Note that the strings already exists and we are just pointing to them. A new reference only.
A new example: building char** copy as a full copy of niz
It is very very important to see the difference here: copy points to an array of pointers, but each pointer points to a copy of the corresponding string declared in niz and referenced in the sample array.
// building 'copy' as an array of pointers to the strings once in niz
char** copy = NULL; // ok, points to nothing
copy = (char**) malloc(area);
for( int i=0; i<n; i+=1)
{
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) );
// large enough to hold it
int j = 0; // copy each letter
for ( ; niz[i][j] != 0; j+=1 ) copy[i][j] = niz[i][j];
copy[i][j] = 0; // this terminates the string
}
printf("\n=>\tPrinting the %d copies using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, copy[i]);
Note: it is in general not recommended to cast the pointers return by malloc() in C, as in the lines
copy = (char**) malloc(area);
// or
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) );
I just do not care and prefer to write all them down explicitly, as a reminder to myself of what is what. Sure, in C++ you must declare this, but is is rare to allocate memory this way in C++ since C++11. Fell free to use whatever rule you see fit
A complete example
This is the output
PS C:\src\ifdef> gcc -o teste -Wall -Wextra -Wpedantic -std=c17 so210126.c
PS C:\src\ifdef> ./teste
Total of 8 values
Before: Voda (4)
After: voda
Before: KraISSa (7)
After: kraissa
Before: somsssR (7)
After: somsssr
Before: aaaaa (5)
After: aaaaa
Before: WeWeWeW (7)
After: wewewew
Before: AomsssZ (7)
After: aomsssz
Before: A (1)
After: a
Before: TheLastValue (12)
After: thelastvalue
=> Printing the 8 strings using the pointers
0: 'voda'
1: 'kraissa'
2: 'somsssr'
3: 'aaaaa'
4: 'wewewew'
5: 'aomsssz'
6: 'a'
7: 'thelastvalue'
=> Printing the 8 copies using the pointers
0: 'voda'
1: 'kraissa'
2: 'somsssr'
3: 'aaaaa'
4: 'wewewew'
5: 'aomsssz'
6: 'a'
7: 'thelastvalue'
PS C:\src\ifdef>
I compiled just on gcc 10.2 on Windows.
This is the example code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char v2m(char z) { return z + 0x20; }
void konvertuj(char *niz, int n)
{
for (int i = 0; i < n; i++)
if(niz[i] >= 'A' && niz[i] <= 'Z')
niz[i] = v2m(niz[i]);
}
int main(void)
{
char niz[8][15] =
{
[2] = "somsssR",
[3] = "aaaaa",
[5] = "AomsssZ",
[6] = "A",
[0] = "Voda",
[1] = "KraISSa",
[4] = "WeWeWeW",
[7] = ""
};
int n = sizeof(niz)/sizeof(niz[0]); // total of strings
strcpy( niz[n-1], "TheLastValue"); // changes the last string
printf("Total of %llu values\n", sizeof(niz)/sizeof(niz[0]));
for (int i = 0; i < n; i++)
{
int d = 0;
while ( niz[i][d] != 0) d+=1;
printf("Before: %s (%d)\n", niz[i], d);
konvertuj( niz[i], d );
printf("After: %s\n", niz[i]);
}
// building an array of pointers to the strings in niz
char** sample = NULL; // ok, points to nothing
unsigned area = n * sizeof(char*); // n pointers to strings
sample = (char**) malloc(area);
for( int i=0; i<n; i+=1)
sample[i] = niz[i];
printf("\n=>\tPrinting the %d strings using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, sample[i]);
// building 'copy' as an array of pointers to the strings once in niz
char** copy = NULL; // ok, points to nothing
copy = (char**) malloc(area);
for( int i=0; i<n; i+=1)
{
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) ); // large enough to hold it
int j = 0; // copy each letter
for ( ; niz[i][j] != 0; j+=1 ) copy[i][j] = niz[i][j];
copy[i][j] = 0; // this terminates the string
}
printf("\n=>\tPrinting the %d copies using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, copy[i]);
for( int i=0; i<n; i+=1) free(copy[i]); // destroy each string
free(copy); // destroy the array;
free(sample); // sample points to static memory...
return 0;
}
As for the very very long post: I wanted to leave an example of the
solution plus an example of the steps involved in order to build a char** vector from
existing strings and as an independend copy.
How do I edit a value in an array with pointer in C?
int *pointer;
int array[3][1];
I tried this:
int *Pointer
int array[2][2];
Pointer[1][1]= 6;
but when compiling, I get a segmentation fault error. What to do?
Given some array int Array[Rows][Columns], to make a pointer to a specific element Array[r][c] in it, define int *Pointer = &Array[r][c];.
Then you may access that element using *Pointer in an expression, including assigning to *Pointer to assign values to that element. You may also refer to the element as Pointer[0], and you may refer to other elements in the same row as Pointer[y], where y is such that 0 ≤ y+c < Columns, i.e., Pointer[y] remains in the same row of the array.
You may also use Pointer[y] to refer to elements of the array in other rows as long as none of the language lawyers see you doing it. (In other words, this behavior is technically not defined by the C standard, but many compilers allow it.) E.g., after Pointer = &Array[r][c];, Pointer[2*Columns+3] will refer to the element Array[r+2][c+3].
To make a pointer you can use to access elements of the array using two dimensions, define int (*Pointer)[Columns] = &Array[r];.
Then Pointer[x][y] will refer to element Array[r+x][y]. In particularly, after int (*Pointer)[Columns] = &Array[0]; or int (*Pointer)[Columns] = Array;, Pointer[x][y] and Array[x][y] will refer to the same element.
You can access any given element with this syntax: array[x][y].
By the same token, you can assign your pointer to any element with this syntax: p = &array[x][y].
In C, you can often treat arrays and pointers as "equivalent". Here is a good explanation:
https://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
However, you cannot treat a simple pointer as a 2-d array. Here's a code example:
/*
* Sample output:
*
* array=0x7ffc463d0860
* 1 2 3
* 4 5 6
* 7 8 9
* p=0x7ffc463d0860
* 0x7ffc463d0864:1 0x7ffc463d0868:2 0x7ffc463d086c:3
* 0x7ffc463d0870:4 0x7ffc463d0874:5 0x7ffc463d0878:6
* 0x7ffc463d087c:7 0x7ffc463d0880:8 0x7ffc463d0884:9
*/
#include <stdio.h>
int main()
{
int i, j, *p;
int array[3][3] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
// Dereference 2-D array using indexes
printf("array=%p\n", array);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%d ", array[i][j]);
printf ("\n");
}
// Dereference 2-D array using pointer
p = &array[0][0];
printf("p=%p\n", p);
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++)
printf ("%p:%d ", p, *p++);
printf ("\n");
}
/* Compile error: subscripted value p[0][0] is neither array nor pointer nor vector
p = &array[0][0];
printf("p=%p, p[0]=%p, p[0][0]=%p\n", p, &p[0], &p[0][0]);
*/
return 0;
}
Cast the 2D-array into 1D-array to pass it to a pointer,
And then, You are ready to access array with pointer. You can use this method to pass 2D-array to a function too.
#include <stdio.h>
int main()
{
int arr[2][2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
arr[i][j] = (2 * i) + j;
}
}
int *Pointer = (int *)arr; // Type conversion
/*
&arr[0][0] = Pointer + 0
&arr[0][1] = Pointer + 1
&arr[1][2] = Pointer + 2
&arr[2][2] = Pointer + 3
Dereference Pointer to access variable behind the address
*(Pointer + 0) = arr[0][0]
*(Pointer + 1) = arr[0][1]
*(Pointer + 2) = arr[1][2]
*(Pointer + 3) = arr[2][2]
*/
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d ", *(Pointer + (2 * i) + j)); // Accessing array with pointer
}
printf("\n");
}
return 0;
}
Using the function wv_matalloc from https://www.ratrabbit.nl/ratrabbit/content/sw/matalloc/introduction , you can write the following code:
#include <stdio.h>
#include "wv_matalloc.h"
int main()
{
double **matrix;
int m = 3;
int n = 4;
// allocate m*n matrix:
matrix = wv_matalloc(sizeof(double),0,2,m,n);
// example of usage:
int i,j;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
matrix[i][j] = i*j;
printf("2 3: %f\n",matrix[2][3]);
}
Compile with:
cc -o main main.c wv_matalloc.c
1.
You never assigned a value to Pointer in your example. Thus, attempting to access array by Pointer invokes undefined behavior.
You need to assign Pointer by the address of the first element of array if the pointer shall be a reference:
Pointer = *array;
2.
You can't use 2D notation (p[1][1]) for a pointer to int. This is a C syntax violation.
3.
Since rows of static 2D arrays are allocated subsequent in memory, you also can count the number of array elements until the specific element of desire. You need to subtract the count by 1 since indexing start at 0, not 1.
How does it work?
Each row of array contains 2 elements. a[1][1] (the first element of the second row) is directly stored after the first two.
Note: This is not the best approach. But worth a note beside all other answers as possible solution.
#include <stdio.h>
int main (void)
{
int *Pointer;
static int array[2][2];
Pointer = *array;
Pointer[2] = 6;
printf("array[1][1] (by pointer) = %d\n", Pointer[3]);
printf("array[1][1] (by array istelf) = %d\n", array[1][1]);
}
Output:
array[2][2] (by pointer) = 6
array[2][2] (by array istelf) = 6
Side Notes:
To address the first element of the second row by array[1][2] invokes undefined behavior. You should not use this way.
"but when compiling, I get a segmentation fault error."
Segmentation fault error do not occur at compile time. They occur at run time. It just gives you the impression because high probably your implementation immediately executes the program after compilation.
Hello everyone I just started learning how to use pointers and I got stuck in my code. I need to write a code that modifies(corrects the uppercases and lowercases and finds out the year of every citizen) and sorts a list of citizens. For an example if the user entry is:
4 //just the number of citizens
lAna lanIc 1999
lana lanac 1999
laNa LaneC 1989
lAna lanOc 1999
the display must be :
18; Lanac, Lana
18; Lanic, Lana
18; Lanoc, Lana
28; Lanec, Lana
#include <stdio.h>
#include <string.h>
#include <ctype.h>
typedef struct {
char name[26];
char surname[26];
int birth;
} citizen; //the structer for the citizen
void modify(citizen *g);
int compare(citizen g1, citizen g2); //compares citizens by birth or surname or name
void sort(citizen g[], int); //insertion sort
int main()
{
int n, i;
citizen g[100];
scanf("%d", &n);
for(i = 0; i < n; i++) {
scanf("%s %s %d", g[i].name, g[i].surname, &g[i].birth);
modify(g + i);
}
sort(g, n);
for (i = 0; i < n; i++) {
printf("%2d; %s %s\n", g[i].birth, g[i].surname, g[i].name);
}
return 0;
}
void modify(citizen *g) { //here I'm having trouble
int i = 0;
//trying to correct the name
if(isalpha(*g[i].name[0])) {
*g[i].name[0] = toupper(*g[i].name[0]);
}
for(i = 1; i < strlen(*g[i].name); i++) {
*g[i].name = toupper(*g[i].name);
}
//then the surname
if(isalpha(*g[i].surname[0])) {
*g[i].surnma[0] = toupper(*g[i].surname[0]);
}
for(i = 1; i < strlen(*g[i].surname); i++) {
*g[i].surname = toupper(*g[i].surname);
}
*g[i].birth = 2017 - *g[i].birth; //finding how old is the citizen
}
int compare(citizen g1, citizen g2) {
if(g1.birth == g2.birth) {
if(!strcmp(g1.surname, g2.surname)) {
return strcmp(g1.name,g2.name);
}
else {
return strcmp(g1.surname, g2.surname);
}
}
else if (g1.birth > g2.birth) {
return 1;
}
return -1;
}
void sort(citizen g[], int n) { //insertion sort
int i, j;
citizen tmp;
for(i = 0; i < n; i++) {
tmp = g[i];
j = i;
while(j > 0 && compare(g[j-1], tmp)) {
g[j] = g[j - 1];
j--;
}
g[j] = tmp;
}
}
The basics:
In your main function this:
citizen g[100];
declares an array of 100 citizens. g is an array which is not a pointer.
In your modify function
modify(citizen *g)
g is a pointer to a citizen. It is not an array. So you're probably asking why it is legal to do this:
modify(g + i);
The reason is that, in the context of using g in an expression, it is transformed by the compiler into a pointer to its first element. We say "g decays to a pointer to its first element".
There are two ways to access the thing(s) that a pointer points to (we say "dereference the pointer"). The first is to use the * operator. If p is int* we can do
int x = *p;
If p points to an int that is in an array of ints, we can do pointer arithmetic. So we could do
int y = *(p + 3);
int z = *(p - 2);
If p points to the third element of an array that is at least size 6, y now has the same value as the sixth element and z has the same value as the first element.
The second way to dereference a pointer is to use subscript syntax. The syntax p[i] is exactly equivalent to *(p + i) and I mean exactly. Addition is commutative so p + i == i + p which means *(p + i) == *(i + p) which means (and this is legal in C) p[i] == i[p] Anyway each of the statements above can be written using subscripts
int x = p[0];
int y = p[3];
int z = p[-2];
Except to save our sanity, we tend to only use subscript syntax if p is a pointer to the first element of an array or the first element of a malloc'd block.
If p is a pointer to a struct (like your citizen struct, you can access the fields in the struct by dereferencing p and using the normal diot syntax.
int myBirth = (*p).birth;
The parentheses are necessary because the dot operator normally has higher precedence than the * operator. With *p.birth the C compiler thinks that p s a struct with a field called birth which it tries to dereference as a pointer. C provides a shortcut syntax for the (*p).birth thing which is
int myBirth = p->birth; // Exactly equivalent to (*).birth
Finally in C, you can obtain a pointer to an arbitrary object with the & operator.
int x = 0;
int* p = &x; // p is a pointer to x.
So when we say g decays to a pointer to its first element, what we mean is that the compiler transforms
modify(g + i);
to
modify(&g[0] + i);
So, you see, your modify function receives a pointer to an element of g. Looking at the first couple of lines of the function:
if(isalpha(*g[i].name[0])) {
*g[i].name[0] = toupper(*g[i].name[0]);
}
Because i is 0 at this point, `g[i].name` is the same as `(*g).name` or `g->name`. Use the last one for clarity. The `name` field is an array of chars, so `name[0]` is the first character of the name, which is what you want. You have an extra dereference with the leading * that you don't need. The above should be
if (isalpha(g->name[0])) {
g->name[0] = toupper(g->name[0]);
}
Except toupper does the isalpha check for you, so all that becomes
g->name[0] = toupper(g->name[0]);
I'll leave it to you to fix the rest of the function, except to mention the rather bad bug here:
for(i = 1; i < strlen(*g[i].surname); i++) {
*g[i].surname = toupper(*g[i].surname);
}
This actually makes no sense to me at all.
Instead of dereference pointer your way, I will give you answer here:
void modify(citizen *g) { //here I'm having trouble
int i = 0;
//trying to correct the name
//Is this really necessary?
if (isalpha(g->name[0])) {
g->name[0] = toupper(g->name[0]);
}
for (i = 1; i < strlen(g->name); i++) {
g->name[i] = toupper(g->name[i]);
}
//then the surname
//Is this really necessary?
if (isalpha(g->surname[0])) {
g->surname[0] = toupper(g->surname[0]);
}
for (i = 1; i < strlen(g->surname); i++) {
g->surname[i] = toupper(g->surname[i]);
}
g->birth = 2017 - g->birth; //finding how old is the citizen
}
I've also modify you compare function:
int compare(citizen *g1, citizen *g2) {
if (g1->birth == g2->birth) {
int resp = strcmp(g1->surname, g2->surname);
if (!resp) {
return strcmp(g1->name, g2->name);
}
return resp;
} else if (g1->birth > g2->birth) {
return 1;
}
return -1;
}
I am trying to make a function in C which will swap two string variables but something went wrong and the program crashes.
Please have a look at my code and tell me where I made a mistake:
#include <string.h>
void strswap(char name1[], char name2[]) // to swap two strings
{
int lengthname1, lengthname2;
lengthname1 = strlen(name1);
lengthname2 = strlen(name2);
char temporaryname1[100];
char temporaryname2[100];
int x;
int y;
// till just the declaration
for (int x = 0; x < lengthname1; lengthname1++) {
temporaryname1[x] = name1[x];
name1[x] = ' ';
}
// copying the value of name1 in temporaryname1
for (int y = 0; y < lengthname2; lengthname2++) {
temporaryname2[x] = name2[x];
name2[x] = ' ';
}
// copying the value of name2 in temporaryname2
for (int x = 0; x < lengthname1; lengthname1++) {
name1[x] = temporaryname2[x];
}
for (int y = 0; y < lengthname2; lengthname2++) {
name2[x] = temporaryname1[x];
}
}
#include <stdio.h>
int main()
{
char name[] = "hello";
char name2[] = "hi";
printf("before swapping: %s %s\n", name, name2);
strswap(name, name2);
printf("after swapping: %s %s\n", name, name2);
}
EDIT:- I have corrected the program and it is working properly. Soon my header file is going to work with some other modules. Thank you all for your help and especially to #Micheal
There are many issues:
First issue
The x variable is not initialized:
int x; int y; // first declaration of x
// till just the declaration
for(int x=0;x<lengthname1;lengthname1++)
{// ^ second declaration of x , local to the loop
temporaryname1[x]=name1[x];
name1[x]=' ';
}
// if you use x here it's the first x that has never been initialized
Second issue
This:
for (x = 0; x<lengthname1; lengthname1++)
should be:
for (x = 0; x<lengthname1 + 1; x++)
Why lengthname1 + 1 ? Because you need to copy the NUL char that terminates the string.
There are similar problems in your other for loops as well.
For example here you use y as loop variable, but in the loop you use x:
for (int y = 0; y<lengthname2 + 1; lengthname2++)
{
name2[x] = temporaryname1[x];
Third issue
In main you declare this:
char name[] = "hello";
char name2[] = "hi";
That is actually the same as
char name[6] = "hello"; // 5 chars for "hello" + 1 char for the terminating NUL
char name2[3] = "hi"; // 2 chars for "hi" + 1 char for the terminating NUL
Now even if your strswap is correct, you are trying to stuff the 6 bytes from the name array ("hello") into the 3 bytes array name2, there is not enough space in the name2 array. This is undefined behaviour.
And last but not least:
This is simply useless:
name1[x] = ' ';
And finally
You should ask yourself why you need two temporary strings (temporaryname1 and temporaryname2) in strswap() - one is enough.
void strswap(char ** name1, char ** name2)
{
char * name1_1 = malloc(strlen(*name2) + 1);
char * name2_1 = malloc(strlen(*name1) + 1);
strncpy(name1_1, *name2, strlen(*name2) + 1);
strncpy(name2_1, *name1, strlen(*name1) + 1);
*name1 = name1_1;
*name2 = name2_1;
}
int main()
{
char * name="hello";
char * name2="hi";
printf("before swapping %s %s\n",name,name2);
strswap(&name, &name2);
printf("after swapping %s %s\n",name,name2);
return 0;
}
Actually following is the safest way to swap two strings. In your cases, you were statically using strings of size 100 in size, which is not good and work in all case. Moreover, You tried to use ' ' instead of '\0' to mark end of string. String APIs uses '\0' to indicate that string has ended.