Tricky C function testing knowledge static, global, local variables and pointers - c

Disclaimer: Yes this is a homework problem. I'm having a particularly difficult time understanding what the function f2 does.
#include <stdio.h>
int i = 10; /* global variable */
int j = 1; /* global variable */
/* Forward function declarations */
void swap(int, int); int f1(int);
void f2(int, int *);
int main()
{
{
int i = 1;
int j = 10;
swap(i,j); printf("i = %d j = %d\n", i,j);
j = f1(i++); printf("i = %d j = %d\n", i,j);
f2(f1(i),&j); printf("i = %d j = %d\n", i,j);
//which j does this refer to? The static variable, global, or local and why
}
j = f1(i/2); printf("i = %d j = %d\n", i,j);
f2(f1(i),&j); printf("i = %d j = %d\n", i,j);
return 0;
}
void swap(int a, int b)
{
int temp;
temp=b; b=a; a=temp;
}
int f1(int x)
{
static int j = 5;
i++;
j+=x;
return j;
}
void f2(int x, int *p)
{
*p+=x;
*p = (*p>20) ? 20 :*p++;
}
When I run this code into the compiler, I get the following answer:
i = 1 j = 10
i = 2 j = 6
i = 14 j = 14
i = 13 j = 14
i = 14 j = 20
I understand the first set of i and j, the reason being swap does nothing because the variables a and b are deleted in the heap.
For the second set, we increment the i in main and then we use the value 1 as x because i++ is post-increment. We create a static variable j, the global variable x gets increased to 11, and it returns j as 6 because x is added to j. After the function is completed, the i variable in the main gets incremented to 2. This leads to 2 and 6.
For the third print statement, I first call f1(i) which is equal to two, this resets j to 5 and increments the global variable i to 12. Then j gets set to 7 and we return 7 for f1(i). Then this is the part I am having difficulty on. We then pass the memory location of j as the parameter, but which j do we pass and why? From the output it seems as if the static j's memory is being passed but I'm not sure.
As we go into the function f2, we get *p+=x, which I believe gives the value 14 because x is set to 7 from earlier and j is also 7. What I do not get is the second line: "*p = (*p>20) ? 20 :*p++;". What does this even mean? From the output it seems to have copied the value of j into i.
What does the second line of code in the function f2 do and which j (the bolded one with a & sign in front of it) is called in the line "f2(f1(i),&j); printf("i = %d j = %d\n", i,j);".

The instructions of f2 do the following:
*p+=x;
This adds the value of x to whatever is stored at the location pointed to by p. The * dereferences pointer p.
*p = (*p>20) ? 20 :*p++;
If the value stored at p is larger than 20, then store 20 at p. Otherwise store the value of p at p and increment p, which is undefined behavior (pointed out by Cool Guy), as *p++ is equivalent to *p = *p; p++;

Related

Pointer arithmetic in C not pointing to the correct variables if I don't print the address of the variables

So I'm doing pointer arithmetic homework and I need to decrement and increment pointers with this as its expected outcome. This is what I did
#include <stdio.h>
void main(void){
int d = 10;
int c = 8;
int b = 6;
int a = 4;
int *ptr; //these lines are given
printf("decrement \n");
for (ptr = &d; ptr >= &a; ptr--)
{
printf("%d \n",*ptr);
}
printf("increment \n");
for (ptr = &a; ptr <= &d; ptr++)
{
printf("%d \n",*ptr);
}
}
But the results skip 8 and 6:
decrement
10
4
increment
4
10
And so I decided to print the addresses at the beginning to help debug
printf("%p\n",(void*)&d);
printf("%p\n",(void*)&c);
printf("%p\n",(void*)&a);
printf("%p\n",(void*)&b);
But after running it, it just works
000000fc6a9ffb34
000000fc6a9ffb30
000000fc6a9ffb28
000000fc6a9ffb2c
decrement
10
8
6
4
increment
4
6
8
10
So I know that the logic works out, but it just doesn't work without printing first and I don't know why
I'm using Vscode and GCC
So I know that the logic works out, but it just doesn't work without printing first
Undefined behavior (UB), anything may happen.
int d = 10;
int a = 4;
int *ptr = &d;
ptr >= &a
ptr >= &a is undefined behavior (UB).
Order comparisons of pointers in C are UB when not part of the same array (or one after).
ptr-- is also UB as that attmepts to form the address before d. Pointer math only good within an array/object (or one after)
In your first example, you are not using variables b and c, just a and d - therefore (I suspect) the implementation is optimizing them away
In the second example, you are using variables all four variables a, b, c and d therefore they cannot be optimised away
your program have four different variables not an array of size four. So address of variables is unpredictable.
int d = 10;
int c = 8;
int b = 6;
int a = 4;
in Array memory is allocated contiguously, so use array if you want to do so.
#include<stdio.h>
int main(){
int arr[4] = {1, 2, 3, 4};
// increment
for(int i=0; i<4; i++)
printf("%d\n",*(arr + i));
// decrement
printf("-------------------------------\n");
for(int i=3; i>=0; i--)
printf("%d\n",*(arr + i));
return 0;
}

How do i use a pointer in C to return a value?

I am trying to make a pointer P return to me the index of the first occurrence of given number in an array using count function that i wrote (J's job is to return the number of occurrences), the idea here is that im trying to write a function that returns 2 values instead of 1 (P returns index of first occurrence and J returns its number) in such way:
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
}
I am fully aware aware that instead of using int *p, i can simply use P and pass its address in such way:
void printarray(int h[],int size){
for(int i=0;i < size ;i++)
{
printf(" %d ",h[i]);
}
printf("\n");
}
int count(int h[],int *p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
*p=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int p;
int h[] = {1,2,3,4,5,1,1,3,4};
printarray(h,sizeof(h)/sizeof(int));
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", p,j);
}
What Really intrigues me is that why does it show a segmentation fault when using the pointer ? or am i just wrong about using a pointer in the first place and i should pass the address of an int in case i want my function to return 2 values for me ?
That which is a pointer has to point to something. So when you wrote int *p = NULL; you didn't give it somewhere to point. You could have done int n; int *p = &n; and proceed to pass p.
But it gets bumpy from here. You tried to write p = &i; inside the function. While that's completely valid code, from that point, assigning to *p will mess up your loop control function. This is not what you want. In the "I know I can" section you have the more reasonable *p = i;.
I'm guessing you want to know how to pass something allocated in the function to its caller. You can in fact do this; there's standard library functions designed for this task. You can in fact write
int count(int h[],int **p,int size,int d)
{
int j=0;
int bool = 0;
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
*p = malloc(sizeof(int));
**p = i;
}
else if(h[i]==d)
j++;
}
if(bool==0)
{
j=-1;
return j;
}
else
return j;
}
void main ()
{
int j;
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, &p , sizeof(h)/sizeof(int) , 1);
if (p) {
printf("%d %d", *p,j);
free(p);
} else {
printf("(no index) %d", j);
}
}
So what happened here is we have a pointer in main() that is initialized to point nowhere, may or may not be set in count to point to the index. If nothing is found, p will still point to NULL (nowhere). The function malloc() returns the newly allocated memory so that p has somewhere to point; and the function free returns it.
** is a simple idea that gives people headaches. Since a pointer is * we add another * when we want a pointer to a pointer, so we can change that pointer. Just don't ask how deep you can go. The answer is don't try. Two happens a lot; three requires a good justification, and more than three is almost never done. More than two really is a headache and nobody wants headaches on their headaches. The limit is way higher. Nobody goes there.
It probably seems rather pointless, and it is. malloc() is used to allocate entire arrays in the function (whose size isn't known until runtime) and return them to the caller. A single int just isn't worth managing like this (the pointer is bigger than it is), but for an array it makes sense. So much that in big programs, almost everything is on the heap; unlike the small programs everybody starts with where almost everything is on the stack (local variables are on the stack).
You thinking about what you want to do correctly, but you are over complicating how to do it a bit. Instead of all the if ... else ... statements, what if you just used a flag like what you call bool (but let's rename it to something that won't conflict with the type from stdbool.h), call it first_set instead. Initialize it with a value of 0 (false) to begin with, and then when you find the first occurrence, update first_set = 1;
If you step back and thing of what your primary check needs to be, all you are really worried about locating in your array is the first, and all remaining indexes where the given value (let's call val instead of d) is equal to the array element. (and since a count, a length and an array index cannot be negative, let's choose size_t as the type for the positive counting values). To track the number of occurrences, let's use occurs as the variable (helps keep things readable in long programs)
So all you really want to do is loop over each element in your array and check if the current element is equal to the value you are searching for. That is the primary concern from which all other actions can be taken. You can keep your parameters in the order you like, but I find it easier to think about the function (1) taking an array, (2) of a given number of elements, where I will find (3) the first occurrence or (4) a given value. (whatever makes sense to you, but is also readable to whoever works on your code later) So with a slight tweak of the ordering (at least for my old eyes), you could set up your function to loop over each element and locate all of the occurrences of a given value as:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
...
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
The only thing left to add is how to set the first occurrence. While you talk in terms of locating the "address" of the first occurrences in the function, what I think you really mean is locating the "index" of the first occurrence within the array. You can convert the index back to an address in the calling function and not have to worry about passing something that can hold the address (which would require passing a pointer-to-pointer rather than a pointer-to int)
So the first time the test of a[i] == val tests true, you want to capture the index and save it, ensuring you don't change it for any of the other times a[i] == val tests true during your loop. You have your first_set flag that is currently set to 0 (false), so all you really need to capture your first index in the array where val occurs is:
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
If you put that in place of the ... placeholder in the function above, you would have:
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
Short and sweet, no else needed, just a check of your flag first_set and if it isn't set, capture the index and set first_set true so you don't change in during the remainder of your loop. Your function makes the index of the first occurrence of val available back in the calling function by updating the value at the address held by the pointer first. The function returns the total number of occurrences for val in your array so it too is available to the caller. (with a slight change of type to size_t)
(another benefit of using size_t on platforms where size_t is larger than int is your array (or allocated block) can hold more than INT_MAX values and your code will still work without risk of integer overflow if a count exceeds what can be represented by an int)
Putting it altogether in a short example that creates an array of 100 elements holding random values from -10 to 10 and then chooses the value to find by choosing a random value in that range, you could check that all works as expected as follows:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NELEM 100 /* if you need a constant, #define one (or more) */
#define PERROW 10
#define LO_LIM -10
#define HI_LIM 10
int rand_in_range (int lowlim, int highlim)
{
return rand() % (highlim - lowlim + 1) + lowlim;
}
void arr_fill_rand (int *a, size_t nelem, int lowlim, int highlim)
{
for (size_t i = 0; i < nelem; i++)
a[i] = rand_in_range (lowlim, highlim);
}
void arr_prn (int *a, size_t nelem, const char* fmt)
{
const char *format = fmt != NULL ? fmt : " %d";
for (size_t i = 0; i < nelem; i++) {
if (i && i % PERROW == 0)
putchar ('\n');
printf (format, a[i]);
}
putchar ('\n');
}
size_t arr_occurrences (int *a, size_t nelem, size_t *first, int val)
{
int first_set = 0; /* flag if 1st occurrence set */
size_t occurs = 0; /* total no. of occurrences */
for (size_t i = 0; i < nelem; i++) { /* loop over each element */
if (a[i] == val) { /* is it equal to val? */
if (!first_set) { /* if first not set */
*first = i; /* update value at address of first */
first_set = 1; /* set first_set flag true */
}
occurs += 1; /* increment no. of occurrences */
}
}
return occurs; /* return total number of occurrences */
}
int main (void) {
int arr[NELEM] = {0}, /* array of NELEM set all zero */
val = 0; /* value to find */
size_t first = 0, /* index of first occurrence */
occurs = 0; /* total no. of occurrences */
srand (time(NULL)); /* seed random number generator */
val = rand_in_range (LO_LIM, HI_LIM); /* random in LO to HI (inclusive) */
arr_fill_rand (arr, NELEM, LO_LIM, HI_LIM); /* fill with random values in range */
arr_prn (arr, NELEM, " % 3d");
occurs = arr_occurrences (arr, NELEM, &first, val); /* get occurrences of val */
printf ("\n%d occurs first in array of %d " /* output results */
"elements ranging from %d to %d at:\n"
" index : %zu\n"
" address : %p\n"
"and occurs a total of %zu times.\n",
val, NELEM, LO_LIM, HI_LIM,
first, (void*)&arr[first], occurs);
}
(note: you never need more than one call to printf() (or fputs() or puts()) to provide on block of output, regardless of the number of lines it contains. You can keep things readable in longer output by breaking the string up into adjacent strings (newlines and other whitespace between them is ignored) and the compiler with create a single string to output from all adjacent string literals)
Example Use/Output
The program outputs the array and then outputs the results with the index of the first occurrence (and it's actual address if that is what you wanted) along with the total number of times the value of interest was found:
$ ./bin/arr_rand_1st_occ+count
3 -10 2 10 2 -9 4 5 -3 7
-4 -6 10 -4 8 -5 8 5 -10 10
10 6 -3 2 -5 1 1 8 10 -1
6 0 -1 -5 -1 10 -6 -10 4 1
5 -10 6 5 -4 1 8 -8 -4 8
-9 -7 2 -4 5 7 5 -7 3 4
2 -4 -6 10 1 1 9 5 0 0
-7 -6 -2 9 7 3 -2 4 3 4
2 4 5 -9 8 -3 6 2 0 -2
-6 -10 4 -2 8 -8 7 6 5 -4
8 occurs first in array of 100 elements ranging from -10 to 10 at:
index : 14
address : 0x7ffea2fb5938
and occurs a total of 7 times.
The array is output with 10 values PERROW to make things easier to read. Remember when confirming the results, arrays are zero-indexed in C.
Last note is unless you are programming in a freestanding environment (without the benefit of any OS), the allowable declarations for main for are int main (void) and int main (int argc, char *argv[]) (which you will see written with the equivalent char **argv). See: C11 Standard - §5.1.2.2.1 Program startup(p1). See also: What should main() return in C and C++?
In a freestanding environment (such as programming on a microcontroller) without the benefit of an operating-system, the name and type of the function called at program startup are implementation-defined. See: C11 Standard - 5.1.2.1 Freestanding environment
Look things over and let me know if you have further questions.
Your program behaviour is undefined because it end up dereferencing a NULL pointer here:
int *p = NULL;
int h[] = {1,2,3,4,5,1,1,3,4};
j = count(h, p , sizeof(h)/sizeof(int) , 1);
printf("%d %d", *p,j);
^^
|
Dereferencing p which is a NULL pointer
The way you are passing the p pointer from main() function to count() function, you are passing NULL. That means, in context of your program, this
j = count(h, p , sizeof(h)/sizeof(int) , 1);
is equivalent to this
j = count(h, NULL , sizeof(h)/sizeof(int) , 1);
The count() function parameter p will receive NULL as argument i.e. it's equivalent to p = NULL (where p is count() function parameter).
Whatever you assign to p in count() function, you are actually modifying a local variable of count() function. No changes are going to reflect in pointer variable p of main() function and it will remain a NULL pointer.
Now, lets come to the count() function.
In this snip of code of count() function:
for(int i=0; i<size ;i++)
{
if(h[i]==d && bool == 0)
{
j++;
bool = 1;
p = &i;
}
else if(h[i]==d)
j++;
}
the scope and life of loop variable i is within the for loop block. Once, the loop exit the lifetime of i is ended. JFYI - accessing an object outside of its lifetime is undefined behaviour. So, if p hold &i and out of loop body if your program access p then it will lead to undefined behaviour. Also, *p=-1; statement in count() will also lead to undefined behaviour because, in count() function p will be a NULL pointer if bool==0.
Remember, if a function is passing a pointer to another function as a argument and expecting that function to modify the value of pointer, which it receive as parameter, then the pointer should be pointing to a valid memory location before the calling function access and modify it's memory contents or the caller function should pass address of pointer as argument and let the calling function allocate memory dynamically to it so that it should be accessible from the caller function as well (which is main() function, in your case).
There are couple ways to achieve this.
Method I:
Pass a valid memory location to calling function.
Either pass address of a local variable of caller function as argument (this is same as your second code snippet)
int main (void) {
int j;
size_t res = 0;
size_t *p = &res; // p is pointing to res variable
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
return 0;
}
Or allocate memory to pointer in caller function and pass it
int main (void)
{
int j;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 1;
p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE); // or whatever you want to do in case of allocation failure
}
j = count (h, p, sizeof (h) / sizeof (int), num);
if (j != -1) {
printf ("%zu %d", *p, j);
} else {
printf ("%d not found\n", num);
}
free(p);
return 0;
}
and the count() function implementation for both the above cases:
int count (int h[], size_t *p, size_t size, int d) {
int j = 0;
for (size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if (j == 0) {
*p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
Method II:
Pass the address of p and dynamically allocate memory to p in count() function before accessing it. Note that, objects with allocated storage duration live until they are destroyed by a call to free(). So, if count() function allocates memory to a pointer, whose address passed as argument to count() function from main() function, then that memory will be accessible in main() function as well via pointer variable p.
#include <stdio.h>
#include <stdlib.h>
int count (int h[], size_t **p, size_t size, int d) {
int j = 0;
for(size_t i = 0; i < size ; ++i) {
if(h[i] == d) {
if ((j == 0) && (p != NULL)) {
*p = malloc (sizeof (size_t));
if (p == NULL) {
fprintf (stderr, "Failed to allocate memory");
exit (EXIT_FAILURE);
}
**p = i;
}
++j;
}
}
return j == 0 ? -1 : j;
}
int main (void) {
int retval;
size_t *p = NULL;
int h[] = {1, 2, 3, 4, 5, 1, 1, 3, 4};
int num = 3;
retval = count (h, &p, sizeof (h) / sizeof (int), num);
if (retval != -1) {
printf ("%zu %d\n", *p, retval);
} else {
printf ("%d not found\n", num);
}
// free memory once you are done with it
if (p != NULL) {
free (p);
}
return 0;
}
Additional:
Using void as return type of main function is not as per standards. The return type of main function should be int.
You are trying to return pointer pointing to a place which will be no longer valid once the loop completed it's execution, either declare i outside for or don't use the pointer part, as dereferencing a null pointer is illegal, also, you get segmentation fault when you try to access memory you have no business with and no permission to read or write, in this case, pointing to a memory location which is out of scope.
Instead of returning a pointer,simply create a local array of same type in the function, first index for first occurence of the given number, and second index for the total occurence, and return the array but make sure the return type should be pointer of same type.
edit: thanks Mr. Joshua, for pointing out the mistake.

Why the output is not 0,1.Why it is 0,2.?

#include<stdio.h>
void f(int *p, int *q)
{
p = q;
*p = 2;
}
int i = 0, j = 1;
int main()
{
f(&i, &j);
printf("%d %d \n", i, j);
getchar();
return 0;
}
This code prints 0,2,why it does'nt print 0,1 because after *p=2 the value of j is assigned 1 right?can anyone help me
Inside f you are assigning the pointer p the pointer value of q.
Means - after p = q;, both p and q point to the same int which is j.
That's why you get 0,2.
"after *p=2 the value of j is assigned 1 right?"
No, function f() ends at the closing } brace, and
j was assigned the value of 1 before main() begins.
The line
int i = 0, j = 1;
could equally well be further up, before function f().
"because after *p = 2; the value of j is assigned by 1 right?"
No. You seem to confuse here something very hard in terms of control flow and scope. The definition of f is placed before the definitions of the global variables i and j.
That doesn't mean that the global variables get assigned after the function.
int i = 0, j = 1;
are definitions of i and j (declaration with immediate initializations) at global scope, not assignments.
The value of j 2 after the call to f is correct because:
j is passed by reference to f and its address is assigned to the pointer parameter q.
The value of the pointer q is assigned to the pointer p.
p is dereferenced then which points to j in the caller and assigns 2 to j.
Here is what happens:
statement i j p q
-----------------------------------------
int i = 0, j = 1; 0 1 - -
f(&i, &j); 0 1 &i &j
p = q; 0 1 &j &j
*p = 2; 0 2 &j &j
printf("%d %d \n", i, j); 0 2 - -

How to use pointer to bidimensional array C

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.

All elements in array being set to last element in C?

sorry if this is a stupid question but I'm having an issue where all the elements of my array are being set to the last element in C. I think I'm overriding something and would like another pair of eyes. My goal is create an array of random numbers of type char. Code is below:
int main(int argc, char *argv[]) {
unsigned int seed = atoi(argv[1]);
printf("seed = %d\n", seed);
srand(seed); //NOTE: i seed random from the command line
unsigned char *p[8];
for(int i = 0; i < 8; i++){
int random_number = rand() % 255;
char random_number_string[8];
itoa(random_number, random_number_string, 10);
p[i] = random_number_string;
//below is just to check
printf("p[%d] = %s\n", i, p[i]);
}
// below i comment out irrelevant parts of the code
//unsigned char byte0[8];
//itoa( (rand() % 256), byte0, 10);
//printf("byte0 = %s\n", byte0);
//printf("Binary values: \n");
for(int n = 0; n < 8; n++){
printf("p[%d] = %s\n", n, p[n]);
//PRINTBIN((int)p[i]);
//printf("\n");
}
return 0;
The result of all this is:
seed = 1054480
p[0] = 81
p[1] = 66
p[2] = 36
p[3] = 32
p[4] = 81
p[5] = 245
p[6] = 33
p[7] = 72
p[0] = 72
p[1] = 72
p[2] = 72
p[3] = 72
p[4] = 72
p[5] = 72
p[6] = 72
p[7] = 72
I'm just wondering what I'm doing to overwite all those values. Thanks.
In your code, p is an "array" of 8 pointers to char. This means that you are storing an address location in the array p.
If you print the addresses along with the data like so -
printf("p[%d] = %s\n", i, p[i]);
printf("%d\n", p[i]);
You will notice that all the values in the array (p) are same, i.e. all the elements in the array are "same" and that is exactly what is your output shows from the second for() loop. This address is the address of the local variable random_number_string.
The first loop is printing different data as the first loop is changing the data in every iteration and after the last iteration, this address location contains the "last" value set.
Hope this clarifies the behavior that you are seeing.
Each iteration of the first cycle creates a new instance of its local char random_number_string[8]; array and then destroys it at the end. On each iteration of that cycle you are storing a pointer to the beginning of that random_number_string array in p[i]. Each pointer p[i] becomes "sour" (dangling) at the end of each i-th iteration. Thus all p[i] values end up invalid. Any attempts to access these values result in undefined behavior.
And this is exactly what your second cycle does. The behavior of your program is undefined.
Note, BTW, that it is incorrect to say that all of your array elements point to the same memory location (as some answers here do). Your array p contains invalid, indeterminate pointer values. Nothing definitive can be said about these values.
Each iteration of your first loop defines 'char random_number_string[8]' and the space for this is allocated from the stack frame. Each iteration does not increase the size of the stack frame, but is going to reuse the same stack space as the prior iteration, meaning that each time around random_number_string will be found at exactly the same address. And since you are placing the address of random_number_string into every element of your 'p' array, every element holds the same value. Whatever you place at that address will be pointed to by every element in your array.
But there's another, issue with your code. You have placed the address of an auto variable into another data structure, The problem is that stack frame that contained random_number_string is popped off the stack at the end of each iteration of your first loop, and will be reused by subsequent stack frames / code blocks.
If you know in advance the maximum size of all of these strings, then you can simply pre-allocate the lot of them with a two dimensional array. Here is the code written with this approach:
int main(int argc, char *argv[]) {
unsigned int seed = atoi(argv[1]);
printf("seed = %d\n", seed);
srand(seed); //NOTE: i seed random from the command line
unsigned char p[8][10];
for(int i = 0; i < 8; i++){
int random_number = rand() % 255;
itoa(random_number, p[i], 10);
printf("p[%d] = %s\n", i, p[i]);
}
for(int n = 0; n < 8; n++){
printf("p[%d] = %s\n", n, p[n]);
}
return 0;
}
Alternatively, you could dynamically allocate them (from the heap). Depending your program, you may need to free them when you are done with them.
int main(int argc, char *argv[]) {
unsigned int seed = atoi(argv[1]);
printf("seed = %d\n", seed);
srand(seed); //NOTE: i seed random from the command line
unsigned char *p[8];
for(int i = 0; i < 8; i++){
int random_number = rand() % 255;
p[i] = (unsigned char *)malloc(10 * sizeof(unsigned char));
itoa(random_number, p[i], 10);
printf("p[%d] = %s\n", i, p[i]);
}
for(int n = 0; n < 8; n++){
printf("p[%d] = %s\n", n, p[n]);
}
return 0;
}

Resources