C - Pointers, Arrays and Memory Management

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 47

Chapter 2: Arrays and Pointers

1
Content

• 2.1. Array
• 2.1.1. Array variable types
• 2.1.2. Multidimensional arrays
• 2.1.3. Strings
• 2.2. Pointers
• 2.2.1. Pointer variable types
• 2.2.2. Pointers vs arrays
• 2.2.3. Dynamic Memory allocation

2
2.1. Array

3
2.1.1. Array variable types

• Used to store a finite set of elements


• of the same type (primitive or object)
• adjacent to each other in memory
• Each array has a name
• The elements are numbered

Array name

Index
Declaration and Initialization

 Specify number of dimensions, size of array, type of elements

Declaration (1D array)


type array_name [N] ;
type array_name [N] = {v1,v2,…,vn};
type array_name [] = {v1,v2,…,vn};
v1,v2,…,vn: initial values for elements

int a[10];
Declaration and Initialization

• 1D array
char s[20];
char s[10] = {‘s’, ‘t’, ‘r’, ‘i’, ‘n’, ‘g’};
char s[10] = “string”; //  char s[10] = {’s’,’t’,’r’,’i’,’n’,’g’,’\0’};

int a[10] = {1,2,3}; //  int a[10] = {1,2,3,0,0,0,0,0,0,0};

int a[3] = {}; //  int a[3] = {0,0,0};

int a[] = {1,2,3}; //  int a[3] = {1,2,3};

int a[] ; //error


Constant array

const type array_name [N] = {v1,v2,…,vn};


type const array_name [] = {v1,v2,…,vn};

• All elements in the array are constants.


• Initialization of elements when declared is mandatory.

Exp: const int a[3] = {1,2,3};


a[1] = 5 ; //error

7
Indexing and element access

• Access element: index operator []


• starting with 0
• each element like a single variable of type T

8
Example:

Program to sort an array of N numbers in ascending order using bubble sort algorithm

main(){
const int N = 200 ;
float a[N] ;
int i,j ;
… // input values for array a ;
for (i=0;i<N-1;i++)
for (j=0;j<N-i-1;j++)
if (a[j]>a[j+1]) {
float tg = a[j];
a[j]=a[j+1];
a[j+1] =tg;
}
… // print the result
}
2.1.2. Multidimensional array

• An array may have any number of dimensions


• 2D array:
type array_name [M][N] ;
type array_name[M][N] = {v1,v2,…,vm*n};
type array_name[][N] = {v1,v2,…,vm*n};
• int m[5][9]; the array a has 5 rows and 9 columns
• Both rows and columns are indexed from 0
• To access the element of m in row i and column j: m[i][j]

10
2.1.2. Multidimensional array

• C stores arrays in row-major order, with row 0 first, then row 1 and so on

• Initializer a 2D array by nesting 1D initializers


2.1.2. Multidimensional array

// The initializer fills only the first three rows of m, the last two rows
will contain 0

// If an inner list isn't long enough to fill a row, the remaining


elements in the row are initialized to 0
2.1.2. Multidimensional array

• Omit the inner braces


• compiler collects enough values to fill 1st row, then fills the next, and so
on
2.1.2. Multidimensional array

char s [2][3];
//  int a[2][3] = {1,2,3,4,5,0};
int a[][3] = {1,2,3,4,5};
int a[2][3] = {{1,2},{3,4,5}}; //  int a[2][3] = {{1,2,0},{3,4,5}};

int a[2][] ; //error

int a[2][] = {1,2,3,4,5}; //error


typedef syntax

• Define new data type based on existing data type


• or redefine the name of existing data type
• Syntax: typedef old_type new_type ;
• Example:
• typedef int integer ;
integer i,j ;
• // for array
typedef char ten[30] ; // ten is new alias for array of 30 char
ten t1=”An”,t2=”Binh”,t3; //  char t1[30], t2[30], t3[30] ;

• typedef float f1[N] ;


typedef f1 f2[M] ;
typedef f2 f3[L] ; //  typedef float f3[L][M][N] ;
sizeof operator with arrays

• sizeof() determines the size of an array


• Example:
• int a[10];
• int s = sizeof(a); // s = 40 if sizeof(int)=4
• int n = sizeof(a)/sizeof(int); // number of elements
2.1.3. C-String

• An array of characters, ending with the character '\0'


• char ten[5] = "Tung";
char ten[5] = {'T', 'u', 'n', 'g', '\0' };
• char str5[5] = {'l', 'i', 'n', 'u', 'x'}; /* !!! */
char str6[6] = {'l', 'i', 'n', 'u', 'x', '\0'};
printf("%s %s", str6, str5);

• char str[ ] = "linux";


• char str[5] = "linux"; /* !!! */
• char str[9] = "linux";

• char ntca1[10] = “Bob”; // ok, this is initialization, not assignment


• char ntca[10];
ntca = “bob”; //No, illegal!!

17
2.1.3. C-String

• #include <stdio.h>
scanf("%s", ten)  Read until you encounter a space
scanf("%[^\n]", ten);  include spaces, read to enter character
gets(name);

• #include <string.h>
int strlen(s)  calculate string length
int strcmp(str1, str2)  compare 2 strings, result: 1, 0, -1
char* strcpy(dest, src) copy src (upto \0) to dest
char ntca[10];
ntca = “bob”; //No, illegal!!
strcpy(ntca, “bob”); // ok

char* strcat(dest, src) concatenate src to dest

These functions will allow the user to walk off the array => Pay attention !

18
Limitations of array

• Homogeneous (đồng nhất): no array can have values of two data


types.
• Declaring the array size is compulsory, and the size must be a
constant.
• Thus there is either shortage or waste of memory.
• In C, the array does not check its boundaries
• no check to see if the values entered are exceeding the size of
the array.
• Data exceeding the array size will be placed outside the array
=> big problem !

19
2.2. Pointers

20
2.2.1. Pointer variable types

• A special variable used to store the address of other variables.


• to store the address of a single variable, array, structure, union,
or even another pointer
• The size of the pointer = the size of an int

• Roles of pointers:
• Manage dynamic data objects and dynamic storage structures
• to increase speed and flexibility of locating and accessing

21
Declaration

• Declaration: operator *
• T * var;
• Example:
• int *ip; int* ip; int * ip; /* pointer to an integer */
• double *dp; /* pointer to a double */
• char *ch /* pointer to a character, or a string */
• int *pi, j; // pi: pointer to an integer, j: int
• int* pi, j; // pi: pointer to an integer, j: int
• int *pi, *j; // pi, j: pointers to an integer

22
Address operator

• Address operator ‘&’: to get address of a variable


• to assign value to pointer
• int *pInt, *pInt2, iNT3;
pInt2 = pInt;
pInt2 = &iNT3;

char c = ‘A’;
char *pc = &c;
int a[5], *pa;
pa = &a[0];
pa = a;
pa = (int*)pc; // type conversion

pa = 10; // dangerous !!!

23
Indirection/access/dereference operator

• Indirection/access/dereference operator
• access the memory region that the pointer points to
• 3 kind of access operators
• * operator: for char, int, float/double
int a ;
int * pi = &a ;
*pi = 20 ;

• [] operator: for array type


char s[10] ;
char * ps = s ; //ps  s[0], s  s[0]
ps[0] = ‘H’ ;
ps[1] = ‘I’ ;
ps[2] = ‘\0’ ;

•  operator: for struct type (view later)

24
Indirection/access/dereference operator

• & is the “inverse” operator of *


• For any variable a, *&a is equivalent to a,
• If p is a pointer then &*p is also equivalent to p

(No meaning)

25
Example

• char c = 'A';
int *pInt;
short s = 50;
int a = 10;

pInt = &a;
*pInt = 100;

Address 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511

Variable char c int *pInt short s int a …

Value 'A' 1507 50 10  100 …

Addressing variables in memory


in ascending order here is for
illustrative purposes only

26
Math operations with pointers

• Increment/Decrement: to change the pointer to the next position (corresponding


to the type size it points to)
Address 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511

p-- short *p p++


(1502) (1504) (1506)

• Address addition: also corresponds to the type it points to


Address 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511

p-2 short *p p+3


(1500) (1504) (1510)

• Comparison: 2 pointers of the same type can be compared to each other as two
integers (large, small, equal)
• Two pointers of the same type can be subtracted to get the different number of
elements

27
void * (pure/general pointer)

• Is a pointer but does not carry type information


• Can be implicitly cast to any other pointer type

• Do not use indirection operator * with void pointer

• The void * pointer is used to work with pure memory or to


manipulate variables of undefined type

28
Constant Pointers and Pointers to Constant

• const T * ptr = <exp>; // Pointer variable points to a constant


T const * ptr = <exp>;
• T * const ptr = <exp> ; // A constant pointer to a variable
• const T * const cons3 = <exp>; // A constant pointer to a constant
const char* pc= “abcd” ;
char * s = “fgh” ;
pc[1] = ‘f’; //error const char* const cpc = “abcd”;
pc = “efgh”; //OK cpc[1] = “f” ; //error
pc = s ; //OK cpc = “efgh”; //error
cpc = s ; //error

char* const cp = “abcd”;


cp[1] = “f” ; //OK
cp = “efgh”; //error
cp = s ; //error

29
NULL pointer

• A pointer constant pointing to no address in memory


• Depending on the standard library, Null pointers are usually = 0 (NULL)
• Cannot assign a value to a NULL pointer
• int *pInt = NULL
*pInt = 100; /* lỗi */
• Check the validity of a pointer variable.
if (p != NULL)
if (p)
if(!p)

30
Pointer to pointer

• One pointer can point to another pointer:


• float x = 1.5;
float *pX = &x;
float **ppX = &pX;
printf("%f", **ppX); /* 1.5 */
ppX pX x
1.5

**ppX = 2.3;
ppX pX x
2.3

31
2.2.2. Pointers vs. arrays

• Array is a static pointer (can't change array address)


• Array name is a constant pointer = address of (pointer to) the first element
of the array
• An array variable can be manipulated like a pointer, except by assigning a
new address to it
int arr[] = {1, 2, 3, 4, 5};
int x;
*arr = 10; /*  arr[0] = 10; */
printf("%d", *(arr+2)); /* arr[2] */
arr = &x; /* error */

• Pointers can be manipulated like an array


int *p = arr;
p[2] = 20; /*  arr[2] = 20; */
p = arr+2; /*  p = &arr[2]; */
p[0] = 30; /*  arr[2] = 30; or: *p = 30; */

32
2.2.2. Pointers vs. arrays

• Using pointers on 2-dimensional arrays


• Address Formula
arr[i][j] address = arr[0][0] address + [(i x no_of_cols + j) x size_of_data_type]

• Element access, using pointers


• 1st way: arr[i][j] = *((int *)arr + (i x no_of_cols + j))
• 2nd way: arr[i][j] = ((int *)arr)[i x no_of_cols + j]

www.dyclassroom.com

33
2.2.2. Pointers vs. arrays

• Element access, using pointers


• 3rd way:
• int zippo[4][2]; // an array of arrays of ints
• zippo: address of the first element of the array zippo  address of zippo[0]
 address of zippo[0][0]
• zippo: address of a two-int-sized object ; zippo[0]: address of an int-sized
object
• zippo+1 will be different from zippo[0]+1
• *(zippo[0]): represents the value stored in zippo[0][0]

*(*(zippo+2) + 1) = zippo[2][1]

34
2.2.2. Pointers vs. arrays

• Differences:
• Unable to assign new address to array variable
• Array variables are allocated memory for elements (in the stack)
right from the time of declaration
• The sizeof() operator with arrays indicates the actual size of the
array, while with pointers it gives the size of the pointer itself
• float arr[5]; sizeof(arr) = ?
• float* p = arr; sizeof(p) = ?
• sizeof(arr)/sizeof(arr[0]) ?
• use negative indices with pointer
• int arr[] = {1, 2, 3, 4, 5};
int *p = arr + 2;
p[-1] = 10; /*  arr[1] = 10; */

35
2.2.2. Pointers vs. arrays

• Array of pointers

36
2.2.2. Pointers vs. arrays

• Pointers to arrays
• declare a pointer variable pz that can point to a 2D array like zippo?
• int (*pz)[2]; // pz points to an array of 2 ints
• int * pz[2]; // pz is array of 2 pointers of int
[] has a higher precedence than * => need parentheses

37
2.2.2. Pointers vs. arrays

• Pointer and String


• char ten[5] = "Tung"; (initialize an array by pointer/string)
• char ten[5] = {'T','u','n','g','\0' }; (initialize an array
by array)
• char *ten = "Tung"; (initialize a pointer by pointer/string)
• char *ten = {'T', 'u', 'n', 'g', '\0' }; /* wrong
*/

char *strstr(s1, s2)  return the position of string s2 in s1 or NULL

38
Example

39
2.2.3. Dynamic Memory allocation

• The program declares data objects (variable or constant) of some


data type:
• located in static memory (stack) and storage size is fixed
• Dynamic data type:
• the storage size can change over its lifetime, depending on time
when it's used in the program.
• located in dynamic memory (heap)

40
2.2.3. Dynamic Memory allocation

• Memory allocation:
• #include <stdlib.h>
• void *malloc(int size) ;
• size: number of bytes to be allocated, return address of that
allocation
• int *p = (int *)malloc(10*sizeof(int)); /*allocate 10 ints */
• void *calloc(int num_elem, int elem_size) ;
• size = num_elem * elem_size
• void *realloc(void* ptr, int new_size)
• reallocate new size for the memory allocation pointed by ptr
• Allocation may be failed and return NULL  need to check
• Free the allocated memory
• void free(void *p);
• free(p);

41
Example

• int *x;
x = (int *)malloc(50 * sizeof(int));
free(x);

• struct employee
{
char *name;
int salary;
};
typedef struct employee emp;
emp *e1;
e1 = (emp *)calloc(30,sizeof(emp));

• int *x;
x = (int *)malloc(50 * sizeof(int));
x = (int *)realloc(x,100); //allocated a new memory

42
Working with string

• Working with dynamic memory allocation


• remember to ‘\0 ‘

• strlen only returns the length of the character string, not counting
'\0'
• Declare pointer does not create memory for pointer to point to

43
Error when using pointer

• Must control the address to which the pointer points


• Consequent:
• Do not use uninitialized pointers
• assign pointers = NULL when it has not been initialized
• Only assign address of already created variables to pointers to
ensure that pointers always point to valid memory locations
• Must check the length of the memory to ensure that it is not
exceeded (buffer overflow error)
• When the allocated memory is no longer in use, it must be
destroyed/free so that it can be used again

44
Summary

• Pointers makes C stronger, but once used incorrectly, debugging is


very difficult  need to master and use pointers flexibly
• Pointers are also used a lot in the following cases:
• Passing the value from the function out through the parameter
• Function pointers
• Data structures: linked lists, queues, dynamic arrays, etc.

45
Exercises

1. Viết chương trình:


• Nhập một số nguyên N
• Cấp phát một mảng N số nguyên và nhập dữ liệu cho nó
• In ra màn hình mảng đó theo thứ tự ngược lại
2. Cho mảng một chiều, vào dữ liệu mảng từ bàn phím và tính tổng các phần tử
của mảng
3. Cũng bài 2, nhưng sử dụng con trỏ
4. Viết chương trình nhập chuỗi s1, sau đó copy s1 vào chuỗi s2 dùng mảng
5. Viết chương trình nhập 2 chuỗi s1 và s2, sau đó so sánh xem s1 và s2 có giống
nhau không, dùng mảng
6. Viết chương trình nhập một mảng số thực chưa biết trước số phần tử, và cũng
không nhập số phần tử từ đầu (nhập đến đâu mở rộng mảng tới đó)

46
Exercises

1. Write a program:
• Enter an integer N
• Allocate an array of N integers and input data to it
• Print the array in reverse order
2. Given a one-dimensional array, enter the array data from the keyboard and
sum for all elements of the array.
3. Do exercise 2, but using pointers
4. Write a program to input a string s1, then copy s1 into string s2, using array
5. Write a program to input two strings, s1 and s2, and then compare if they are
the same, using array
6. Write a program to input an array of real numbers without knowing the
number of elements in advance, and also do not enter the number of
elements from the beginning (each time you enter a new number, expand the
array there)

47

You might also like