Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Precedence, Parentheses, Pointers with iterative array functions

Tags:

c

I'm teaching myself a little C and have run across an exercise that I want to make sure I understand completely. The exercise is asking me to pass a pointer to a multidimensional array of integers to a function and iterate through the array. So I started with a print function before moving on to one taking input to populate the array. I tried all sorts of things but after finding a bit of code on type casting and iterating pointers I have the below program that seems to work but I'm not quite understanding what is going on. In my comments I have questions labeled 1-3, referring to the questions below the code. I was hoping someone more intelligent than myself could enlighten me.

//passing multi-Array to a simple print function
#include <stdio.h>

//simple print function prototype
void printMyArr(int (*pt)[4]);

int main()
{
    //declare and initialize a multi-array. I picked 4x4 and some arbitrary 
    //numbers for simplicity's sake

    int myArr[4][4] = { {12, 16, 19, 20}, 
                        {5, 99, 102, 200}, 
                        {12, 20, 25, 600},
                        {65, 66, 999, 1000} };

    //declare a pointer to an array of integers and an int for a loop counter
    int (*pt)[4], counter;

    //initialize the pointer
    pt = myArr;

    //for loop calling printMyArr function to iterate through arrays -- or this is what I understand it to mean
    for(counter=0; counter<4; counter++)
        printMyArr(pt++);   //<-------------Question 1
    return 0;
}

//function called to print array elements to the console
void printMyArr(int(*pt)[4])
{
    //declare a counter....and apparently another pointer
    int counter, *p;

    //initialize new pointer to old pointer and type cast array as int
    p = (int *)pt;          //<-------------Question 2

    //for loop to iterate through elements of array -- or this is what I understand it to mean
    for(counter=0; counter<4; counter++)
        printf("\n\n\n%d", *p++);  //<------Question 3
}

Question 1: Here, I've passed the pointer to the function and I keep thinking, "What is this loop iterating over?". Am I correct in thinking that I am incrementing the pointer to each of the first elements in each array (myArr[0][0], myArr[1][0], myArr[2][0], myArr[3][0])? Also, am I correct in assuming that the syntax of this line is in essence saying: "Execute the function passing the current pointer and THEN when it's done, increment the pointer."?

Question 2: This is what has me the most confused. After quite a bit of digging I found this bit to make it run right and I realize this is how it works, but why?

Question 3: Am I correct thinking that I am incrementing each element here?

So

1: pass pointer as assigned -> myArr[0][0] then print the values in myArr[0][0], myArr[0][1], myArr[0][2], and myArr[0][3], then increment pointer myArr[1][0]

2: pass pointer as assigned ->myArr[1][0] then print the values in myArr[1][0], myArr[1][1], myArr[1][2] and myArr[1][3] increment pointer to myArr[2][0]

3: pass pointer as assigned ->myArr[2][0] then print the values in myArr[2][0], myArr[2][1], myArr[2][2] and myArr[2][3] increment pointer to myArr[3][0]

4: pass pointer as assigned ->myArr[3][0] then print the values in myArr[3][0], myArr[3][1], myArr[3][2] and myArr[3][3] increment pointer to myArr[4][0] and if this is the case what is the pointer pointing to since there shouldn't be a myArr[4][0]?

like image 699
Dan Avatar asked Oct 17 '22 08:10

Dan


2 Answers

Question 1: Here, I've passed the pointer to the function and I keep thinking, "What is this loop iterating over?". Am I correct in thinking that I am incrementing the pointer to each of the first elements in each array (myArr[0][0], myArr[1][0], myArr[2][0], myArr[3][0])?

more or less. pt starts at the address of myArr. You know there's 4 things in the array so you loop 4 times, incrementing pt after accessing it (read below) every time to pass to printMyArr each of the 4 elements of the "top level", "outer" array. Then printMyArr iterates over the 4 elements of the inner array to show each number.

Also, am I correct in assuming that the syntax of this line is in essence saying: "Execute the function passing the current pointer and THEN when it's done increment the pointer."?

Functionally, yes. Technically the order of operations looks like this:

1) get the value of pt 2) increment pt 3) call function, passing the previous value of pt from step 1

pt is incremented as part of the pt++ call, but pt++ evaluates to the old value. As an argument to a funciton, pt++ must be evaluated before the function it's passed to runs. But the timing looks the same as it evaluating directly after the function runs for your case.

Let's take questions 2 and 3 together because they're both part of the answer.

Question 2: This is what has me the most confused. After quite a bit of digging I found this bit to make it run right and I realize this is how it works, but why?

Question 3: Am I correct thinking that I am incrementing each element here?

p = (int *)pt;          
for(counter=0; counter<4; counter++)
    printf("\n\n\n%d", *p++);  

p stores an address of an integer. You set it to the address of the first element of the inner array (which is the address of the inner array itself, so to speak). Then, knowing you have 4 elements in the array, you'r able to loop 4 times, doing a similar pointer post-increment operation on p that you did with pt on the outer array.

The first iteration, p is the same as pt, the address of the first of 4 integer values in memory. *p, dereferencing the pointer, gets the first integer. *p++, due to order of operations ( ++ being of the highest precedence, and dereferencing * being lower), returns the integer at p, leaving p pointing to the next integer address for the next loop.

In general, casting values in C should be avoidid whenever possible. You merely have to do a dereference here to point p to the set of integers. pt holds the address of one of 4 addresses ( outer array ) of contiguous sets of 4 integers (inner array) in memory. The value at *pt is the address of the "current" set of 4 contiguous integers in memory. So you can simply say,

int* p=*pt;

Which doesn't arbitrarily cast a type and is very straightforward and clear. (Thanks @WhozCraig)

like image 107
Daniel Farrell Avatar answered Nov 02 '22 22:11

Daniel Farrell


A multy D array is kept in memory as a continuous array so if you have an array [2][2] it will allocate 4 continuous sizeof(int). The reason you need to define array[][COL] is to let the compiler know how the pointer arithmetic should be done.

so- for Q1- you are right, each time you increment you do so for(sizeof(int)*COL). so each time you move by a row.

Q2- now for each row you want to print one int value at a time, so when you have int* p- this means each increment is done by sizeof(int).

Q3- the increment is for the pointer- not the value- its easy to see for yourself if you do another print in your main.

Hope this help, good luck!

like image 21
H.cohen Avatar answered Nov 03 '22 00:11

H.cohen