You are on page 1of 56

Arrays and Pointers in C

Objectives

Be able to use arrays, pointers, and strings in


C programs

Be able to explain the representation of these


data types at the machine level, including
their similarities and differences

Arrays and Pointers 2


Arrays in C

All elements of same type – homogenous

Unlike Java, array size in declaration

int array[10]; Compare: C: int array[10];


int b; Java: int[] array = new int[10];
First element (index 0)
array[0] = 3; Last element (index size - 1)
array[9] = 4;
array[10] = 5;
array[-1] = 6;

No bounds checking!
Allowed – usually causes no obvious error
array[10] may overwrite b

Arrays and Pointers 3


Array Representation
Homogeneous  Each element same size – s bytes
 An array of m data values is a sequence of ms bytes
 Indexing: 0th value at byte s0, 1st value at byte s1, …

m and s are not part of representation


 Unlike in some other languages
 s known by compiler – usually irrelevant to programmer
 m often known by compiler – if not, must be saved by
programmer

0x1008 a[2]
0x1004 a[1] int a[3];
0x1000 a[0]

Arrays and Pointers 4


Array Representation
char c1;
int a[3];
char c2;
int i;

0x1014 i
0x1010 c2
0x100C a[2] Could be optimized by
a[1] making these adjacent,
0x1008
and reducing padding
a[0] (by default, not)
0x1004

0x1000 c1
Array aligned by
size of elements

Arrays and Pointers 5


A Simple Program Using Array

main( )
{
int avg, sum = 0 ;
int i ;
int marks[30] ;
/* array declaration */
for ( i = 0 ; i <= 29 ; i++ )
{
printf ( "\nEnter marks " ) ;
scanf ( "%d", &marks[i] ) ;
/* store data in array */
}
for ( i = 0 ; i <= 29 ; i++ )
sum = sum + marks[i] ; /* read data from an array*/
avg = sum / 30 ;
printf ( "\nAverage marks = %d", avg ) ;
}

Arrays and Pointers 6


For understanding the arrays properly, let us consider
the following program:

main( )
{
int x ;
x=5;
x = 10 ;
printf ( "\nx = %d", x ) ;
}

Note :- Only single value will be stored in one


variable .so, to overcome array is used

Arrays and Pointers 7


Array Sizes

int array[10];

What is

sizeof(array[3])? 4
returns the size of
an object in bytes
sizeof(array)? 40

Arrays and Pointers 8


practice

main( ) {
int i = 3, *x ;
float j = 1.5, *y ;
char k = 'c', *z ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of j = %f", j ) ;
printf ( "\nValue of k = %c", k ) ;
x = &i ;
y = &j ;
z = &k ;
printf ( "\nOriginal address in x = %u", x ) ;
printf ( "\nOriginal address in y = %u", y ) ;
printf ( "\nOriginal address in z = %u", z ) ;
x++ ; y++ ; z++ ;
printf ( "\nNew address in x = %u", x ) ;
printf ( "\nNew address in y = %u", y ) ;
printf ( "\nNew address in z = %u", z ) ;
}

Arrays and Pointers 9


output

Value of i = 3
Value of j = 1.500000
Value of k = c
Original address in x = 65524
Original address in y = 65520
Original address in z = 65519
New address in x = 65526
New address in y = 65524
New address in z = 65520

Cox / Fagan Arrays and Pointers 10


Facts

(a) Array elements are always stored in


contiguous memory locations.
(b) A pointer when incremented always points
to an immediately next location of its type.

Cox / Fagan Arrays and Pointers 11


practice

main( ) {
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\nelement no. %d ", i ) ;
printf ( "address = %u", &num[i] ) ;
}
}

Arrays and Pointers 12


element no. 0 address = 65512
element no. 1 address = 65514
element no. 2 address = 65516
element no. 3 address = 65518
element no. 4 address = 65520
element no. 5 address = 65522

Cox / Fagan Arrays and Pointers 13


main( ) {
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\naddress = %u ", &num[i] ) ;
printf ( "element = %d", num[i] ) ;
}
}

Cox / Fagan Arrays and Pointers 14


main( ) {
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i, *j ;
j = &num[0] ; /* assign address of zeroth
element */
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\naddress = %u ", j ) ;
printf ( "element = %d", *j ) ;
j++ ; /* increment pointer to point to next
location */ }
Cox / Fagan Arrays and Pointers 15
output

address = 65512
element = 24
address = 65514
element = 34
address = 65516
element = 12
address = 65518
element = 44
address = 65520
element = 56
address = 65522
element = 17
Cox / Fagan Arrays and Pointers 16
Passing an Entire Array to a
Function
Demonstration of passing an entire array to a function */
main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ; dislpay ( &num[0], 6 ) ;
}
display ( int *j, int n )
{
int i ;
for ( i = 0 ; i <= n - 1 ; i++ )
{
printf ( "\nelement = %d", *j ) ;
j++ ; /* increment pointer to point to next element */
}
}

Arrays and Pointers 17


practice
main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17
};
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\naddress = %u ", &num[i] ) ;
printf ( "element = %d %d ", num[i], *( num + i ) ) ;
printf ( "%d %d", *( i + num ), i[num] ) ;
}
}

Arrays and Pointers 18


output

address = 65512 element = 24 24 24 24


address = 65514 element = 34 34 34 34
address = 65516 element = 12 12 12 12
address = 65518 element = 44 44 44 44
address = 65520 element = 56 56 56 56
address = 65522 element = 17 17 17 17

Cox / Fagan Arrays and Pointers 19


Multi-Dimensional Arrays

0x1014 matrix[1][2]
0x1010 matrix[1][1]
int matrix[2][3];
0x100C matrix[1][0]
0x1008 matrix[0][2]
matrix[1][0] = 17;
0x1004 matrix[0][1]
0x1000 matrix[0][0]
Recall: no bounds checking

What happens when you write: “Row Major”


Organization

matrix[0][3] = 42;

Arrays and Pointers 20


main( ) {
int stud[4][2] ;
int i, j ;
for ( i = 0 ; i <= 3 ; i++ )
{ printf ( "\n Enter roll no. and marks" ) ;
scanf ( "%d %d", &stud[i][0], &stud[i]
[1] ) ; }
for ( i = 0 ; i <= 3 ; i++ )
printf ( "\n%d %d", stud[i][0], stud[i]
[1] ) ; }

Arrays and Pointers 21


practice

main( )
{
int s[4][2] = { { 1234, 56 }, { 1212, 33 },
{ 1434, 80 }, { 1312, 78 } } ;
int i ;
for ( i = 0 ; i <= 3 ; i++ )
printf ( "\nAddress of %d th 1-D array = %u",
i, s[i] ) ;
}

Arrays and Pointers 22


Output

Address of 0 th 1-D array = 65508


Address of 1 th 1-D array = 65512
Address of 2 th 1-D array = 65516
Address of 3 th 1-D array = 65520

Cox / Fagan Arrays and Pointers 23


Practice

main( )
{
int s[4][2] = { { 1234, 56 }, { 1212, 33 },
{ 1434, 80 }, { 1312, 78 } } ;
int i, j ;
for ( i = 0 ; i <= 3 ; i++ )
{ printf ( "\n" ) ;
for ( j = 0 ; j <= 1 ; j++ )
printf ( "%d ", *( *( s + i ) + j ) ) ;
}
}
Arrays and Pointers 24
output

1234 56
1212 33
1434 80
1312 78

Arrays and Pointers 25


practice
main( ) {
int s[5][2] = { { 1234, 56 }, { 1212, 33 }, { 1434,
80 }, { 1312, 78 }
};
int ( *p )[2] ;
int i, j, *pint ;
for ( i = 0 ; i <= 3 ; i++ ) { p = &s[i] ;
pint = p ;
printf ( "\n" ) ;
for ( j = 0 ; j <= 1 ; j++ )
printf ( "%d ", *( pint + j ) ) ;
}
}

Arrays and Pointers 26


output

1234 56
1212 33
1434 80
1312 78

Arrays and Pointers 27


Variable-Length Arrays

int
function(int n)
{
int array[n];

New C99 feature: Variable-length arrays


defined within functions

Global arrays must still have fixed (constant) length

Arrays and Pointers 28


Memory Addresses

Storage cells are typically viewed as being


byte-sized
 Usually the smallest addressable unit of memory
• Few machines can directly address bits individually
 Such addresses are sometimes called byte-
addresses
Memory is often accessed as words
 Usually a word is the largest unit of memory access
by a single machine instruction
• CLEAR’s word size is 8 bytes (= sizeof(long))
 A word-address is simply the byte-address of the
word’s first byte

Arrays and Pointers 29


Pointers

Special case of bounded-size natural numbers


 Maximum memory limited by processor word-size
 232 bytes = 4GB, 264 bytes = 16 exabytes

A pointer is just another kind of value


 A basic type in C

int *ptr;

The variable “ptr” stores a pointer to an “int”.

Arrays and Pointers 30


Pointer Operations in C

Creation
& variable Returns variable’s memory address
Dereference
* pointer Returns contents stored at address
Indirect assignment
* pointer = val Stores value at address

Of course, still have...

Assignment
pointer = ptr Stores pointer in another variable

Cox / Fagan Arrays and Pointers 31


Using Pointers

int i1;
int i2;
int *ptr1; 0x1014 … 0x1000
int *ptr2;
0x1010 ptr2:
i1 = 1; 0x100C … 0x1000
i2 = 2; 0x1008 ptr1:
0x1004 i2: 2
3
ptr1 = &i1;
ptr2 = ptr1; 0x1000 i1: 3
1

*ptr1 = 3;
i2 = *ptr2;

Arrays and Pointers 32


Using Pointers (cont.)
int int1 = 1036; /* some data to point to */
int int2 = 8;

int *int_ptr1 = &int1; /* get addresses of data */


int *int_ptr2 = &int2;

*int_ptr1 = int_ptr2;

*int_ptr1 = int2;

What happens?

Type check warning: int_ptr2 is not an int

int1 becomes 8
Arrays and Pointers 33
Using Pointers (cont.)
int int1 = 1036; /* some data to point to */
int int2 = 8;

int *int_ptr1 = &int1; /* get addresses of data */


int *int_ptr2 = &int2;

int_ptr1 = *int_ptr2;

int_ptr1 = int_ptr2;

What happens?

Type check warning: *int_ptr2 is not an int *

Changes int_ptr1 – doesn’t change int1


Cox / Fagan Arrays and Pointers 34
Pointer Arithmetic
pointer + number pointer – number

E.g., pointer + 1 adds 1 something to a pointer

char *p; int *p;


char a; int a;
char b; int b;

p = &a; p = &a;
p += 1; In each, p now points to b p += 1;
(Assuming compiler doesn’t
reorder variables in memory)

Adds 1*sizeof(char) to Adds 1*sizeof(int) to


the memory address the memory address

Pointer arithmetic should be used cautiously

Arrays and Pointers 35


A Special Pointer in C

Special constant pointer NULL


 Points to no data
 Dereferencing illegal – causes segmentation fault

 To define, include <stdlib.h> or <stdio.h>

Arrays and Pointers 36


Generic Pointers

void *: a “pointer to anything”


type cast: tells the compiler to
void *p; “change” an object’s type (for type
int i; checking purposes – does not modify
char c; the object in any way)
p = &i;
p = &c; Dangerous! Sometimes necessary…
putchar(*(char *)p);

Lose all information about what type of thing


is pointed to
 Reduces effectiveness of compiler’s type-checking
 Can’t use pointer arithmetic

Arrays and Pointers 37


Pass-by-Reference

void
set_x_and_y(int *x, int *y)
{

*x = 1001;
*y = 1002; a 1001
1
}
b 1002
2
void
f(void)
{ x
int a = 1;
int b = 2; y

set_x_and_y(&a, &b);
}

Arrays and Pointers 38


Arrays and Pointers
Dirty “secret”: Passing arrays:
Array name  a pointer to the Really int *array
Must explicitly
initial (0th) array element pass the size
int
foo(int array[],
a[i]  *(a + i) unsigned int size)
{
An array is passed to a function … array[size - 1] …
as a pointer }
 The array size is lost!
int
main(void)
Usually bad style to interchange {
arrays and pointers int a[10], b[5];
 Avoid pointer arithmetic! … foo(a, 10)… foo(b, 5) …
}
Arrays and Pointers 39
Arrays and Pointers

int
foo(int array[],
unsigned int size)
{
… What does this print? 8
printf(“%d\n”, sizeof(array));
... because array is really
}
a pointer
int
main(void)
{
int a[10], b[5];
… foo(a, 10)… foo(b, 5) … What does this print? 40
printf(“%d\n”, sizeof(a));
}

Arrays and Pointers 40


Arrays and Pointers

int i; int *p;


int array[10]; int array[10];

for (i = 0; i < 10; i++) for (p = array; p < &array[10]; p++)


{ {
array[i] = …; *p = …;
} }

These two blocks of code are functionally equivalent

Arrays and Pointers 41


Example Code
int x = 1, y = 2, z[10];
int *ip; // ip is a pointer to an int, so it can point to x, y, or an element of z

ip = &x; // ip now points at the location where x is stored


y = *ip; // set y equal to the value pointed to by ip, or y = x
*ip = 0; // now change the value that ip points to to 0, so now x = 0
// but notice that y is unchanged
ip = &z[0]; // now ip points at the first location in the array z

*ip = *ip + 1; // the value that ip points to (z[0]) is incremented

int x, *y, z, *q;


x = 3;
y = &x; // y points to x
printf("%d\n", x); // outputs 3
printf("%d\n", y); // outputs x’s address, will seem like a random number to us
printf("%d\n", *y); // outputs what y points to, or x (3)
printf("%d\n", *y+1); // outputs 4 (print out what y points to + 1)
printf("%d\n", *(y+1)); // this outputs the item after x in memory – what is it?
z = *(&x); // z equals 3 (what &x points to, which is x)
q = &*y; // q points to 3 – note *& and &* cancel out
Example Code
int x = 1, y = 2, z[10];
int *ip; // ip is a pointer to an int, so it can point to x, y, or an element of z

ip = &x; // ip now points at the location where x is stored


y = *ip; // set y equal to the value pointed to by ip, or y = x
*ip = 0; // now change the value that ip points to to 0, so now x = 0
// but notice that y is unchanged
ip = &z[0]; // now ip points at the first location in the array z

*ip = *ip + 1; // the value that ip points to (z[0]) is incremented

int x, *y, z, *q;


x = 3;
y = &x; // y points to x
printf("%d\n", x); // outputs 3
printf("%d\n", y); // outputs x’s address, will seem like a random number to us
printf("%d\n", *y); // outputs what y points to, or x (3)
printf("%d\n", *y+1); // outputs 4 (print out what y points to + 1)
printf("%d\n", *(y+1)); // this outputs the item after x in memory – what is it?
z = *(&x); // z equals 3 (what &x points to, which is x)
q = &*y; // q points to 3 – note *& and &* cancel out
Strings

In C, strings are just an array of characters


 Terminated with ‘\0’ character
 Arrays for bounded-length strings
 Pointer for constant strings (or unknown length)

char str1[15] = “Hello, world!\n”;


char *str2 = “Hello, world!\n”;

C, … He l lo , w o r l d !\n terminator

C terminator: ’\0’

Pascal, Java, … length H el l o, w o r l d ! \n


Arrays and Pointers 44
String length

Must calculate length:


can pass an
int array or pointer
strlen(char str[])
{
array access int len = 0; Check for
to pointer! terminator

while (str[len] != ‘\0’)


len++;
What is the size
of the array???
return (len);
}
Provided by standard C library: #include <string.h>
Arrays and Pointers 45
Pointer to Pointer (char **argv)

Passing arguments to main:


size of the argv array/vector
int
main(int argc, char **argv)
{ an array/vector of
char *
...
} Recall when passing an
array, a pointer to the
first element is passed
Suppose you run the program this way

UNIX% ./program hello 1 2 3

argc == 5 (five strings on the


command line)
Arrays and Pointers 46
char **argv

“3”
0x1020 argv[4]
“2” These are strings!!
0x1018 argv[3] Not integers!
0x1010 argv[2] “1”
0x1008 argv[1] “hello”
0x1000 argv[0]
“./program”

Arrays and Pointers 47


Strings
There is no string type, we implement strings as arrays of
chars
 char str[10]; // str is an array of 10 chars or a string
 char *str; // str points to the beginning of a string of
unspecified length
There is a string.h library with numerous string functions
 they all operate on arrays of chars and include:
• strcpy(s1, s2) – copies s2 into s1 (including ‘\0’ as last char)
• strncpy(s1, s2, n) – same but only copies up to n chars of s2
• strcmp(s1, s2) – returns a negative int if s1 < s2, 0 if s1 = = s2
and a positive int if s1 > s2
• strncmp(s1, s2, n) – same but only compares up to n chars
• strcat(s1, s2) – concatenates s2 onto s1 (this changes s1, but not
s2)
• strncat(s1, s2, n) – same but only concatenates up to n chars
• strlen(s1) – returns the integer length of s1
• strchr(s1, ch) – return a pointer to the first occurrence of ch in s1
(or NULL if ch is not present)
• strrchr(s1, ch) – same but the pointer points to the last
occurrence of ch
• strpbrk(s1, s2) – return a pointer to the first occurrence of any
character in s1 that matches a character in s2 (or NULL if none are
present)
• strstr(s1, s2) – substring, return a pointer to the char in s1 that
starts a substring that matches s2, or NULL if the substring is not
present
Implementing Some of These
void strcpy(char *s, char *t)
int strcmp(char *s, char *t)
int strlen(char *s) {
{
{ int i = 0;
int i;
int n; while((s[i] = t[i]) != ‘\0’)
for(i=0;s[i] = = t[i];i++)
for(n = 0; *s != ‘\0’; s++) i++;
if(s[i] = = ‘\0’)
n++; }
return 0;
return n;
return s[i] – t[i];
}
} void strcpy(char *s, char *t)
{
int strcmp(char *s, char *t) while((*s = *t) != ‘\0’)
{ {
for( ; *s = = *t; s++, t++) s++; t++;
Notice in the second if(*s = = ‘\0’) return 0; }
strcmp and second return *s - *t; }
and third strcpy the }
use of pointers to iterate
through the strings void strcpy(char *s, char *t)
{
The conciseness of the last strcmp and strcpy make them while((*s++ = *t++) != ‘\0’);
hard to understand }
More On Pointer Arithmetic

We can also perform subtraction on pointers

int a[10] = {…};


int *ip;
for(ip = &a[9]; ip >= a; ip--)

Here, we pass to a function the address of the third


element of an array (&a[2]) and use pointer subtraction
to get to a[0] and a[1])
int addem(int *ip)
{
int a[3] = {…}; int temp;
printf(“%d”, addem(&a[2])); temp = *ip + *(ip – 1) + *(ip – 2);
return temp;
}

Recall:
If a is an array, and p = &a[0] then we can reference array
a[0] = *a and elements as a[i], *(p+i), but we can also reference them as
a[i] = *(a + i) p[i] and *(a+i) – that is, a and p are both pointers to the array
And can be dereferenced by * or by [ ]
Multidimensional Arrays
As in Java, C allows multidimensional arrays by using more [ ]
 Example: int matrix[5][10 ];
Some differences:
 Because functions can be compiled separately, we must denote all but
one dimension of a multiple dimensional array in a function’s
parameter list
• void afunction(int amatrix[ ][10]);
 Because arrays are referenced through pointers, there are multiple
ways to declare and access 2+ dimensional arrays
• This will be more relevant when dealing with an array of strings (which is a
2-D array)

int a[10][20]; int *a[3]; // array of 3 pointers


int *a[10]; int x[2] = {1, 2};
int **a; int y[3] = {3, 4, 5};
int z[4] = {6, 7, 8, 9};
*a = &x[0]; // a[0] points to x[0]
*a[4] –first element of 5th array element *(a+1) = &y[0]; // a[1] points to y[0]
*a[9] –first element of 10th array element *(a+2) = &z[0]; // a[2] points to z[0]
**a –first element of a[0] // array a is a jagged array, it is not
// rectangular, or of equal dimensions
Pointers to Pointers

As indicated in the last slide, we can have an array


of arrays which is really an array of pointers or
pointers to pointers
 We may wish to use pointers to pointers outside of
arrays as well, although it is more common that
pointers to pointers represent array of pointers
 Consider the following:

int a; We dereference our pointer p with *p but we dereference


int *p; our pointer to a pointer q with **q
int **q;
a = 10; *q is actually p, so **q is a
p = &a;
q = &p;
printf(“%d”, **q); // outputs 10
Arrays of Strings
Implementation
We could implement an array of strings as a 2-D array of chars
 char array[10][10];
This has two disadvantages
 All strings will be 10 chars long
 Requires 2 nested for-loops for most operations such as string
comparison or string copying, which can become complicated
Instead, we will implement our array of strings as an array of
pointers
 char *array[10];
Each pointer points to one string
 Follow the string through the pointer
 Go to the next string using a for-loop
 Because strcpy, strcmp, strlen all expect pointers, we can use these
by passing an array element (since each array element is a pointer
to a string)
Example
char *x[ ] = {"hello", "goodbye", "so long", "thanks for all the fish"};
// our array of strings x is a set of 4 pointers
char *y; // let y be a pointer to a char so it can be used to move through a single string
int i;
for(i=0;i<4;i++) // iterate for each string in x
{
y = x[i]; // x[i] is an array, x is really a pointer, so this sets y to x’s starting addr.
while(*y!='\0') // while the thing y points to is not the end of a string
{
printf("%c", *y); // print what y points to
y++; // and go on to the next char in x
}
printf("\n"); // separate strings in output with \n
}

Notice that if we had used char x[ ][ ] = {…}; then the


storage space would have been 4 strings of length 23
(the length of the longest string) or 92 bytes instead of
42 bytes as it is above
Passing Arrays

When an array is passed to Because you can compile


a function, what is being functions separately, the
passed is a pointer to the compiler must be able to
array “know” about an array
 In the formal parameter being passed in to a
list, you can either
function, so you must
specify the parameter as
an array or a pointer specify all (or most) of the
definition:
 The type and all dimensions
except for the first
int array[100];
… int array[5][10][15];
afunction(array); …
… afunction(array);

void afunction(int *a) {…} void afunction(int a[ ][10][15]) {…} or
or void afunction(int *a[10][15]) {…} or
void afunction(int a[ ]) {…} void afunction(int a[5][10][15]) {…} or
void afunction(int **a[15]) {…} etc
Some Additional Comments
In functions, do not do return p; where p is a pointer
 Recall local variables are deallocated when the function ends
• so whatever p is pointing to will no longer be available
• but if you return the pointer, then you still are pointing at that memory
location even though you no longer know what is there
We can declare a pointer to point to a void type, which means
that the pointer can point to any type
 However, this does require a cast before the pointer can be
assigned
• int x; float y; void *p; // p can point to either x or y
• p = (int *) &x; // p can point to int x once the address is cast
• p = (float *) &y; // or p can point to float y
Pointers that don’t currently point to anything have the special
value NULL and can be tested as (p = = NULL) or (!p), and (p !
= NULL) or (p)

You might also like