Arrays Pt Rs

41
Arrays and Pointers R. Inkulu http://www.iitg.ac.in/rinkulu/ (Arrays and Pointers) 1 / 41

description

Lecture on arrays and pointers.

Transcript of Arrays Pt Rs

Page 1: Arrays Pt Rs

Arrays and Pointers

R. Inkuluhttp://www.iitg.ac.in/rinkulu/

(Arrays and Pointers) 1 / 41

Page 2: Arrays Pt Rs

Motivation with Example usage

int func(void) {

int states[5], i; //defining

for (i=0; i<5; i++)

states[i]=i; //initializing

for (i=0; i<5; i++)

printf("%d", states[i]); //accessing the value

return 0;

}

• array is used in storing multiple objects of same type

• objects in the array are indexed starting from 0

• array scope is limited to the function in which it is defined

(Arrays and Pointers) 2 / 41

Page 3: Arrays Pt Rs

sizeof() operator

int func(void) {

int a[5];

printf("%d, %d, %d",

sizeof(int), sizeof(a[3]), sizeof(a));

//outputs 4, 4, 20

}

• sizeof(object or type name) is a compile-time unary operator to getsize of an object or a type in number of bytes

(Arrays and Pointers) 3 / 41

Page 4: Arrays Pt Rs

Two-dimensional arrays

int func(void) {

int a[2][3], i, j; //defining

for (i=0; i<2; i++)

for (j=0; j<3; j++)

a[i][j] = i+j; //initializing

for (i=0; i<2; i++)

for (j=0; j<3; j++)

printf("%d, ", a[i][j]); //accessing the value

printf("%d, %d, %d", sizeof(a),

sizeof(a[1]), sizeof(a[1][2]));

//prints 24, 12, 4

return 0;

}

(Arrays and Pointers) 4 / 41

Page 5: Arrays Pt Rs

Three-dimensional arrays

int func(void) {

int a[2][3][4], i, j, k; //defining

for (i=0; i<2; i++)

for (j=0; j<3; j++)

for (k=0; k<4; k++)

a[i][j][k] = i+j; //initializing

for (i=0; i<2; i++)

for (j=0; j<3; j++)

for (k=0; k<4; k++)

printf("%d, ", a[i][j][k]); //accessing

printf("%d, %d, %d, %d", sizeof(a), sizeof(a[1]),

sizeof(a[0][2]), sizeof(a[1][0][2]));

//prints ?

return 0;

}

(Arrays and Pointers) 5 / 41

Page 6: Arrays Pt Rs

Address vs Value

int a, b[2];

a = 10;

printf("%d, %p", a, &a);

//prints 10, 0xbfeac818

b[0] = 22; b[1] = 24;

printf("%d, %p, %d, %p", b[0], &b[0], b[1], &b[1]);

//prints 22, 0xbfeac820, 24, 0xbfeac824

• memory for arrays is allocated contiguously

(Arrays and Pointers) 6 / 41

Page 7: Arrays Pt Rs

Arrays are stored in row-major order

int c[2][3], i, j;

for (i=0; i<2; i++)

for (j=0; j<3; j++) {

printf("%p, ", &c[i][j]);

}

//prints 0xbfd8f650, 0xbfd8f654, 0xbfd8f658,

//0xbfd8f65c, 0xbfd8f660, 0xbfd8f664,

• contiguous memory is allocated for the first row, immediatelythereafter for the second row, etc.,

(Arrays and Pointers) 7 / 41

Page 8: Arrays Pt Rs

Arrays are stored in row-major order (cont)

int a[2][5][3], i, j, k;

for (i=0; i<2; i++)

for (j=0; j<5; j++)

for (k=0; k<3; k++)

printf("%p, ", &a[i][j][k]);

//observed: difference between any two successive

//addresses printed is four

(Arrays and Pointers) 8 / 41

Page 9: Arrays Pt Rs

Initializing arrays while defining

int a[2][5] = {

{0, 11, 22, 33, 44},

{1, 12, 23, 34, 45}

};

for (int i=0; i<2; i++)

for (int j=0; j<5; j++)

printf("%d, ", a[i][j]);

//prints 0, 11, 22, 33, 44, 1, 12, 23, 34, 45,

(Arrays and Pointers) 9 / 41

Page 10: Arrays Pt Rs

Introducing pointers

int x = 1, y = 2, z[2];

int *p = NULL;

//p is a pointer to int, initialized with NULL

p = &x; //p points to x

y = *p; //y is 1

*p = 0; //x is now 0

p = &z[1]; //p points to z[1]

*p = 5; //z[1] is 5

*p = *p + 5; //z[1] is 10

• pointer is jut a variable that saves the address of a memorylocation that contains a specific type

• when p points to a typeA, p is termed as a pointer to typeA

• dereferencing pointer p is denoted with ∗p

(Arrays and Pointers) 10 / 41

Page 11: Arrays Pt Rs

Incrementing a pointer

p z[0] z[1] z[2] z[3]

p z[0] z[1] z[3]q

z[2]

int z[4];

int *p = &z[0];

*(p+1) = 7; //*(p+(1*sizeof(int))) = 7

//i.e., z[1] has 7

p += 2; //p = p + (2*sizeof(int))

*p = 5; //z[2] has 5

*p = *p + 3; //z[2] has 8

*p += 2; //z[2] has 10

++(*p); //z[2] has 11

int *q = p; //q also points to z[2]

*q = 89; //z[2] has 89

• when p is a pointer to typeA, expression p+ i increments p byi ∗ sizeof(typeA)

(Arrays and Pointers) 11 / 41

Page 12: Arrays Pt Rs

Ways to access an array

z+0&z[0]

z[0] z[1] z[2] z[3]

z+2&z[2]

&z[1]z+1

&z[3]z+3

p

p+1

p+2

p+3

*(p+0) *(p+1) *(p+2) *(p+3)p[0] p[1] p[2] p[3]

&p[1]&p[2]

&p[3]

p+0 &p[0]

double z[4], *p = z;

...

z[3] = 10;

...

• ex. compiler replaces z[i] with ∗(z + (i ∗ sizeof(double)))same is true in case of multi-dimensional arrays

(Arrays and Pointers) 12 / 41

Page 13: Arrays Pt Rs

Array name is a pointer

float z[4];

printf("%d, %d, %d", sizeof(p),

sizeof(float), sizeof(*p)); //prints 4, 4, 4

printf("%p, %p, ", z, &z[0]);

//identical values are printed

printf("%p, %p, ", z+1, &z[0]+1);

//identical values (&z[1]) are printed

• name of an array (z) is a synonym for the address of z[0];further, &z[i] + j denotes the address of z[i+ j]

• however, statements like z = p and z++ are illegal as z is not avariable

(Arrays and Pointers) 13 / 41

Page 14: Arrays Pt Rs

Array name is a pointer (cont)

float z[4];

float *p = &z[0], *q;

q = z;

printf("%p, %p, %p", z, p, q);

//identical values are printed

*(z+2) = 20; //z[2] has 20

q[3] = 52; //z[3] has 52

*(q+3) = 58; //z[3] has 58

(Arrays and Pointers) 14 / 41

Page 15: Arrays Pt Rs

More on row-major order of arrays

z[0]

z[1]

z[2]

z[0], z[1], z[2] shown in figure do not occupy additional space

int z[3][4], i, j;

printf("%p, %p, %p, ", z[0], z[1], z[2]);

//prints addresses of three rows i.e, &z[i][0]

printf("%p, %p", &z[2]+1, &z[1]+2);

//prints identical values

printf("%p, %p", z[2]+1, &z[2][1]);

//prints identical values

• two-dimensional array is an array of rows:z[i] is the name of the array that comprises the ith row;and, &z[i] is the address of the first row

(Arrays and Pointers) 15 / 41

Page 16: Arrays Pt Rs

Passing arguments to functions (review)

void func(int y) {

//y has 10

y = 15;

//y has 15

return;

}

int main(void) {

int x=10;

func(x);

printf("%d", x); //prints 10 !

return 0;

}

• function parameters are passed by value

(Arrays and Pointers) 16 / 41

Page 17: Arrays Pt Rs

Simulating pass by reference with pass by value

void func(int *y) {

//now the value of y is the address of x

//(x is a variable defined in main)

*y = 15;

}

int main(void) {

int x=10;

func(&x); //address of x is passed to func

printf("%d", x); //prints 15

}

(Arrays and Pointers) 17 / 41

Page 18: Arrays Pt Rs

Passing arguments to functions: swap func

void swap(int v, int w) {

int tmp = v;

v = w;

w = tmp;

}

int main(void) {

int x=10, y=15;

swap(x, y);

printf("%d, %d", x, y); //prints 10, 15

}

(Arrays and Pointers) 18 / 41

Page 19: Arrays Pt Rs

Simulating pass by reference with pass by value:swap func

void swap(int *v, int *w) {

int tmp = *v;

*v = *w;

*w = tmp;

}

int main(void) {

int x=10, y=15;

swap(&x, &y);

printf("%d, %d", x, y); //prints 15, 10

}

(Arrays and Pointers) 19 / 41

Page 20: Arrays Pt Rs

Passing one-dimensional arrays to functions

int countNonZeros(int v[], int len) {

//v is a pointer to array x (defined in main), and

//len has 3

int count = 0, i;

for (i=0; i<len; i++)

if (v[i] != 0)

++count;

return count;

}

int main(void) {

int x[3] = {20, 30, 0};

int k = countNonZeros(x, 3);

printf("%d", k); //prints 2

}

• change of values of any element of v in countNonZeros gets reflectsin array x of main

(Arrays and Pointers) 20 / 41

Page 21: Arrays Pt Rs

Passing one-dimensional arrays to functions: analternative

int countNonZeros(int *v, int len) {

//v has &x[0], and len has 3

int count = 0, i;

for (i=0; i<len; i++)

if (v[i] != 0)

++count;

return count;

}

int main(void) {

int x[3] = {20, 30, 0};

int k = countNonZeros(x, 3);

printf("%d", k); //prints 2

}

• change of values of any element of v in countNonZeros gets reflectsin array x of main

(Arrays and Pointers) 21 / 41

Page 22: Arrays Pt Rs

Passing partial arrays to functions

int countNonZeros(int *v, int len) {

//v has &x[1], and len has 2

int count = 0, i;

for (i=0; i<len; i++)

if (v[i] != 0) //equivalently, if (*(v+i) != 0)

++count;

return count;

}

int main(void) {

int x[3] = {20, 30, 0};

int k = countNonZeros(&x[1], 2);

printf("%d", k); //prints 1

}

(Arrays and Pointers) 22 / 41

Page 23: Arrays Pt Rs

Passing two-dimensional arrays to functions

void func(double b[][4], int numRows, int numCols)

//equivalently, formal parameter can be b[3][4]

{

...

b[2][3] = 78;

//lvalue is (&b[0][0]+(2*4+2)*sizeof(double))

... }

int main(void) {

double a[3][4];

func(a, 3, 4);

return 0; }

• formal parameter need to include the number of columns; thenumber of rows are irrelevant: since what is passed is, a pointer toan array of rows, where each row is an array of [4] integers (ex. toaccess a particular element, compiler need to be able to calculatethe offset from the beginning of array b)

(Arrays and Pointers) 23 / 41

Page 24: Arrays Pt Rs

Passing multi-dimensional arrays to functions:an alternative

Homework!

(Arrays and Pointers) 24 / 41

Page 25: Arrays Pt Rs

Dynamic Memoryp

double *p = (double *) malloc(count*sizeof(double));

//allocates count*sizeof(double) bytes contiguously;

//p has the address of first byte of those allocated

int i;

for (i=0; i<count; i++) {

p[i] = i*10;

printf("%lf, ", p[i]);

}

//prints 0.000000, 10.000000, 20.000000, 30.000000,

free(p); //frees contigous memory referred by p

• useful when the number of objects to be allocated is not known atcompile-time

• system maintains a table of dynamically allocated memory blocksand their corresp. address ranges

(Arrays and Pointers) 25 / 41

Page 26: Arrays Pt Rs

Dynamic vs non-dynamic memory allocation

z p z[0] z[1] z[2] z[3]

double z[4]; //z is from stack

double *p = (double*) malloc(count*sizeof(double));

//p is from stack, and memory block is from heap

...

free(p);

• memory for auto variables (including arrays) comes from stack,

whereas the dynamic memory comes from heap

of the process address space

(Arrays and Pointers) 26 / 41

Page 27: Arrays Pt Rs

Pointer arithmatic

double *p = (double*)

malloc(count*sizeof(double));

double *q = NULL;

... //denotes irrelevant

//stmts

//i’m here (1)

p += 2;

...

q = p;

//i’m here (2)

...

free(p);

at (1):

p z[0] z[1] z[2] z[3]

q

NULL

at (2):

p z[0] z[1] z[3]q

z[2]

• pointer arithmatic is same whether the memory referred by apointer is either from the stack or heap

(Arrays and Pointers) 27 / 41

Page 28: Arrays Pt Rs

malloc and free pairs

double *p=NULL; int *q = NULL;

...

p = (double*) malloc(countA*sizeof(double));

...

q = (int*) malloc(countB*sizeof(int));

...

free(p);

...

free(q);

• in any program, malloc and free must exist as pairs

avoiding free call corresp. to any malloc call causes memory leak

• malloc and free corresp. to a block of memory

not necessarily be invoked in the same function

not necessarily bracketed

(Arrays and Pointers) 28 / 41

Page 29: Arrays Pt Rs

Dynamic memory: advantages anddisadvantages

advantages:

• useful when the number of objects to be allocated is not known atcompile-time

• gives flexibility to allocate and deallocate memory based on theneed; careful user of this primitive can extract benefits

disadvantages:

• slow due to free/allocated heap space maintainance involvedtogether with the defragmentation overhead

due to intermittent mallocs and frees

• forgetting to deallocate memory causes memory leak

(Arrays and Pointers) 29 / 41

Page 30: Arrays Pt Rs

Non-dynamic memory: advantages anddisadvantages

advantages:

• compiler will deallocate the memory automatically for all theglobal, static, and local memory that it allocated: no memory leakhassles

disadvantages:

• Memory allocation and deallocation are not in the control of user

(Arrays and Pointers) 30 / 41

Page 31: Arrays Pt Rs

Avoid dangling pointers after freeing

...

double *p = (double*)

malloc(count*sizeof(double));

...

//i’m here (1)

free(p);

...

//i’m here (2)

p = NULL;

//i’m here (3)

...

at (1):

p

at (2):

p

dangling

at (3):

p

NULL

• avoid dangling pointers by resetting pointer variable value afterthe free

(Arrays and Pointers) 31 / 41

Page 32: Arrays Pt Rs

Returning pointers from functionsdouble *func(int count) {

double *p = NULL;

...

p = (double*) malloc(count*sizeof(double));

...

return p; }

void func1(int countA) {

int count; double *q = NULL;

...

q = func(count);

...

free(q); //freeing heap memory allocated in func

...

return; }

• heap memory referred by a pointer may require to be freed by thecaller (precise protocol need to be defined)

• does not make sense to return the address of a local variable (ex.array) from a function

(Arrays and Pointers) 32 / 41

Page 33: Arrays Pt Rs

Returning pointers from functions (cont)

void *malloc(size_t sizeInBytes) {

...

}

• void func() returns nothingwhereas void* func() returns pointer to a block of memory (couldbe NULL too) that can contain objects of any type

(Arrays and Pointers) 33 / 41

Page 34: Arrays Pt Rs

Few useful dynamic memory related functionsfrom stdlib.h

void *malloc(size t numBytes)

void free(void *p)

void *calloc(size t numObj, size t sizeOfAObject)

— same as malloc but zeros the memory allocated

void *realloc(void *oldMem, size t numBytes)

— resizes and where necessary relocates the block pointed by p; moves the

contents of *p to the new location; frees the old memory

void *memcpy(void *to, void *from, int numBytes);

— cannot handle the overlap

void *memmove(void *to, void *from, int numBytes);

— same as memcpy but handles the overlap

(Arrays and Pointers) 34 / 41

Page 35: Arrays Pt Rs

Array of pointers to varying sized arrays

STACK HEAP

buf[0]

buf[1]

buf*(buf[0]+2) a.k.a. buf[0][2]

double *buf[2];

buf[0] = (double*) malloc(countA*sizeof(double));

buf[1] = (double*) malloc(countB*sizeof(double));

printf("%d, %d ", sizeof(buf[0]), sizeof(buf));

//prints sizeof(ptr), 2*sizeof(ptr)

...

free(buf[1]);

free(buf[0]);

• buf is an array[2] of pointers, each entry of which points to a blockof memory that contains objects of type double

(Arrays and Pointers) 35 / 41

Page 36: Arrays Pt Rs

Array of pointers to varying sized arrays (cont)

STACK

buf[0]

buf[1]

buf

STACK

z

*(buf[0]+2) or *(buf[1])

double z[4];

double *buf[2];

buf[0] = &z[0];

buf[1] = &z[2];

printf("%d, %d ", sizeof(buf[0]), sizeof(buf));

//prints 4, 8

...

//no need of free calls

(Arrays and Pointers) 36 / 41

Page 37: Arrays Pt Rs

Array of pointers to fixed size arrays

HEAP

*(buf+2)

*(buf+1)

*(buf+0)

(*(buf+1))[1]

buf

STACK

double (*buf)[2] =

(double (*)[2])malloc(count*sizeof(double [2]));

printf("%d, %d, %d, %d",

sizeof(double), sizeof(buf[0]),

sizeof(buf[2]), sizeof(buf));

//prints 8, 16, 16, 4 when count is 3

...

free(buf);

• buf points to count number of array[2]s of doubles

in other words, buf[0] is the zeroth arry[2]; buf[1] is the firstarray[2]; etc.,

(Arrays and Pointers) 37 / 41

Page 38: Arrays Pt Rs

Passing two-dimensional arrays to functions: analternative

void func(double (*b)[4])

//b points to contiguous sequence of double [4]s

{

...

}

int main(void) {

double a[3][4]; //a is an array[3] of array[4]s

func(a);

}

• as mentioned in the past, formal parameter must include thenumber of columns; number of rows are irrelevant

(Arrays and Pointers) 38 / 41

Page 39: Arrays Pt Rs

Passing multi-dimensional arrays to functions:an alternative

Homework!

(Arrays and Pointers) 39 / 41

Page 40: Arrays Pt Rs

Memory layouts of various declarations (review)

(i) double a[2];

double *p = &a[0];

(ii) double *p = (double *) malloc(count*sizeof(double));

(iii) double a[2][3];

(iv) double *a[2];

a[0] = (double *) malloc(countA*sizeof(double));

a[1] = (double *) malloc(countB*sizeof(double));

(v) double *a[2], b[2][3];

a[1] = b[0];

(vi) double (*b)[2];

b = (double (*)[2]) malloc(count*sizeof(double [2]));

(vii) double (*b)[2], c[4][2];

b = c;

homework: using these notions, engineer few more declarations

(Arrays and Pointers) 40 / 41

Page 41: Arrays Pt Rs

to be continued ...

(Arrays and Pointers) 41 / 41