chapter 7 pointers ( 指针 )
DESCRIPTION
Chapter 7 Pointers ( 指针 ). §7.1 Pointer Basics §7.2 Some Special Pointers §7.3 Pointer in Function §7.4 Pointer and String §7.5 “struct” and Linked List §7.6 Function Pointer. §7.1 Pointer Basics. Memory Space. Memory space A “continuous” space Three regions Memory address - PowerPoint PPT PresentationTRANSCRIPT
Chapter 7 Pointers ( 指针 )
§7.1 Pointer Basics
§7.2 Some Special Pointers
§7.3 Pointer in Function
§7.4 Pointer and String
§7.5 “struct” and Linked List
§7.6 Function Pointer
2
§7.1 Pointer Basics
Memory space A “continuous” space Three regions
Memory address Each memory unit has an
address
Variable address The initial address of the
memory allocated for the variable
int i=0;
Code Region
Static Region(Static variables, global
variables, ...)
Dynamic Region(local variables, parameters, ...)
Memory Space
Heap( used by
programmer)Stack(used by system)
…
0xF5B089A0
…
0xF5C08A75
…
0xF5D18995
0xF5E20000
…
3
What’s a Pointer? Pointer:
the variable to hold memory addresses as its value
30
30606 ptr
……
30606
32820
Pointer’s name
Pointer’s addr.
Pointer’s value
Value Pointed
4
Declare a Pointer
Pointer is a composite data type Syntax:
dataType * pointerName;
For example, a pointer named pCount that can point to an int value:
int *pCount;
Pointer type Pointer symbol “*” Pointer name
5
Initialize a Pointer
Implicit initialization A local pointer is assigned an arbitrary value A global pointer is assigned to NULL (pointing nothing)
NULL is in fact “00000000”
Not recommended!May cause fatal runtime error or accidental data modification!Not recommended!May cause fatal runtime error or accidental data modification!
6
Initialize a Pointer
Explicit initialization (recommended)
int count=5;
int *pCount = &count;
int *ptr = NULL;
Address-of operator “&”.The value of “&i” is the address of i.
Address-of operator “&”.The value of “&i” is the address of i.
Address of pCount
Address of variable count Address of variable count
5
pCount count
TestPointerTestPointer RunRun
7
Indirect Reference
Indirection: referencing a value through a pointer.
For example:
int count=5;
int *pCount = &count;
count++; //direct reference
(*pCount)++; //indirect reference
Indirection operator “*”.The value of “*ptr” is the valued pointed by ptr.
Indirection operator “*”.The value of “*ptr” is the valued pointed by ptr.
8
p vs. *p vs. &a
int age;
int *age_ptr = &age;
Then,
age_ptr &age
*age_ptr age
*age_ptr = 50 age = 50;
(*age_ptr)++; age++;
\ *age_ptr++; *(age_ptr++);
9
Operations of Pointer
Operations on the address, not the value pointed Several specific operations
Assignment Movement Subtraction Comparison
The pointer type determines the unit of the operation results
For example:
p±n;// move n*sizeof( pionter type)
10
Examplesvoid main()
{
int a =10, b = 20;
int *pa, *pb;
pa = &a; //Assign the address directly
pb = pa+2;
cout <<"a in: "<< &a <<endl;
cout <<"b in: "<< &b <<endl;
cout <<"pa is: "<< pa <<endl;
cout <<"pa points to: "<< *pa <<endl;
cout <<"pb is: "<< pb <<endl;
cout <<"pb points to: "<< *pb <<endl;
if(pa != pb)
cout <<"pa and pb are not equal!"<<endl;
cout<<"pb - pa is "<<pb-pa<<endl;
}
11
Cautions
The type of the address assigned to a pointer must be consistent with the pointer type.
For example,int area = 1;
double *pArea = &area; The white space besides “*” is optional
int*ptr; int *ptr; int* ptr; int * ptr; One “*” for one pointer
int *ptr1, *ptr2; //two pointers
int* ptr1, ptr2; // one pointer, one integer
12
§7.2 Some Special Pointers
Constant Pointer ( 指针常量) A pointer whose value can not be changed
double radius = 5; double * const pValue = &radius; (*pValue) = 3.0; pValue ++; Pointer of Constant (常量指针)
A pointer that points to a constant
double radius = 5; const double * pValue = &radius; (*pValue) = 3.0; raidus = 3.0
13
Pointer vs. Reference
Reference is alias No separate memory, address Bound with the variable Must be initialized
Pointer is variable Memory, address (of itself) Independent of the variable pointed Can be reassigned different values
14
Pointer and Array
The name of an array represents the starting address
An array variable is essentially a pointer
Address
0xF5B089A0
…
0xF5B089A1
…
0xF5B089A4
“myList” &myList[0]“myList” &myList[0]
myList myList+1 myList+2 …
15
Pointer and Array
You can access city or pCity using the array syntax or pointer syntax. For example,
ArrayPointerArrayPointer RunRun
PointerWithIndexPointerWithIndex RunRun
char city[5]=“GZ”;char *pCity=city;//char *pCity=&city[0];cout << city[1] << endl;cout << *(city + 1) << endl;cout << pCity[1] << endl;cout << *(pCity + 1) << endl;
16
Pointer and Array
Array variable is different from a pointer Array name is a constant (not variable) address
int array[10];
int*ptr=array;
for (k=0; k<5; k++){
cout<< *(ptr++);
cout<< *(array++);
}
17
§7.3 Pointer in Function
Pointer as parameter The address stored in the pointer is passed to the
function A kind of pass-by-reference
TestPointerArgumentTestPointerArgument RunRun
void swap(int *p1, int *p2){ int *temp;
temp = p1;p1 = p2;p2 = temp;
}
void swap(int *p1, int *p2){ int temp;
temp = *p1;*p1 = *p2;*p2 = temp;
}
Pointer as parameter
b, 0028F814b, 0028F814main(){ int *pt1, *pt2; … myswap(pt1, pt2); …}
0028F814
…
0028F820
…
0028F814
…
0028F820
…
8
…
5
…
a, 0028F820a, 0028F820
pt1, 0028F808pt1, 0028F808
pt2, 0028F7ECpt2, 0028F7EC
void myswap(int *p1, int *p2){int *temp;temp = p1;p1 = p2;p2 = temp;
}
p1, 0028F51Dp1, 0028F51D
p2, 0028F711p2, 0028F711
BottomofStack栈底
BottomofStack栈底
对指针本身来讲,是“值传递”;对指针指向的目标来讲,是“引用传递”。对指针本身来讲,是“值传递”;
对指针指向的目标来讲,是“引用传递”。
0028F8140028F814
0028F8200028F820
88
55
19
Pointer as Return Value
The address stored in a pointer is returned
int max=0;int *getMax();
void main(){int *p;p=getMax();cout<<"Max is “<<*p);
}
int *getMax(){int tmp=max, i;
for(i=0;i<3;i++){cout<<"Please enter No.
"<<i<<endl;cin>>tmp;if(tmp>max) max=tmp;
}return &max;
}
Don’t return a local pointer!--it becomes invalid after the return!
WrongReverseWrongReverse
20
Dynamic Memory Allocation
The method allowing programmers to allocate storage Dynamically (during the execution time) and “Manually” (using explicit statement)
“new” operator: to allocate memory
int *pValue = new int;
int *mylist = new int[10];
CorrectReverseCorrectReverse
Allocate memory for an int variable;The address is assigned to “pValue”. Allocate memory for an int variable;
The address is assigned to “pValue”.
Allocate memory for an array of 10 int elements;The address is assigned to “mylist”.
Allocate memory for an array of 10 int elements;The address is assigned to “mylist”.
21
The “delete” Operator
The memory allocated by “new” remains available until you explicitly free it or the program terminates.
“delete”: to free memory reserved by “new”.delete pValue;delete [] mylist;
Memory leak The memory space becomes inaccessible due to the
loss of pointingint *p = new int;p = new int;
It’s good manner to always explicitly free memory allocated by “new”.
It’s good manner to always explicitly free memory allocated by “new”.
(0x00001234)(0x00001234)pp
(0x00001267)(0x00001267)delete p;
22
Case Study: Counting the Occurrences of Each Letter
CountLettersInArrayCountLettersInArray RunRun
Generate 100 lowercase letters randomly and assign to an array of characters.
Count the occurrence of each letter in the array.
…
…
chars[0]
chars[1]
…
…
chars[98]
chars[99]
…
…
counts[0]
counts[1]
…
…
counts[24]
counts[25]
23
§7.4 Pointer and C-string
Two ways to process strings To treat strings as arrays of characters
known as pointer-based strings or C-strings
To process strings using the string class The string class will be introduced in Chapter 9
24
C-string
Two ways to declare C-string Using an array variable
char city[7] = "Dallas";
char city[] = {'D', 'a', 'l', 'l', 'a', 's', '\0' };
char city[] = "Dallas";
cout << city; char city[7]; city= "Dallas";char city[7]; city= "Dallas";
25
C-string using Pointer
Declare a string variable using a pointerchar *pCity = "Dallas";
cout<<pCity;
*(pcity) *(pcity+1)
*(pcity+2)
*(pcity+3)
*(pcity+4)
*(pcity+5)
*(pcity+6)
26
Reading Strings
Using “cin”: can’t read in white space
char city[10];
cin >>city;
Using “getline” : can read any character. a function defined in iostream
cin.getline(char array[], int size, char delimitChar)
char *city2;cin>>city2;char *city2;cin>>city2;
No memory is allocated to store the content of
city2.
No memory is allocated to store the content of
city2.
Where to stop?Where to stop?Where to store?
The last character is reserved for '\0'. Where to store?
The last character is reserved for '\0'.
delimitChar is read but not stored.Default delimitChar is ‘\n’.
delimitChar is read but not stored.Default delimitChar is ‘\n’.
27
String Functions
Function Description
int strlen(char *s1)
Returns the length of the string, i.e., the number of the
characters before the null terminator.
char *strcpy(char *s1, const char *s2)
Copies the string s2 to string s1. The value in s1 is returned.
char *strncpy(char *s1, const char *s2, size_t n)
Copies at most n characters from string s2 to string s1. The
value in s1 is returned.
char *strcat(char *s1, const char *s2)
Appends string s2 to s1. The first character of s2 overwrites the
null terminator in s1. The value in s1 is returned.
char *strncat(char *s1, const char *s2, size_t n)
Appends at most n characters from string s2 to s1. The first
character of s2 overwrites the null terminator in s1 and appends
a null terminator to the result. The value in s1 is returned.
int *strcmp(char *s1, const char *s2)
Returns a value greater than 0, 0, or less than 0 if s1 is greater
than, equal to, or less than s2 based on the numeric code of the
characters.
int *strncmp(char *s1, const char *s2, size_t n)
Returns a value greater than 0, 0, or less than 0 if the n
characters in s1 is greater than, equal to, or less than the first
n characters in s2 based on the numeric code of the characters.
int atoi(char *s1)
Converts the string to an int value.
double atof(char *s1)
Converts the string to a double value.
long atol(char *s1)
Converts the string to a long value.
void itoa(int value, char *s1, int radix)
Converts the value to a string based on specified radix.
28
Character Functions Function Description Example
isdigit(c) Returns true if c is a digit. isdigit('7') is true
isdigit('a') is false
isalpha(c) Returns true if c is a letter. isalpha('7') is false
isalpha('a') is true
isalnum(c) Returns true if c is a letter or isalnum('7') is true
a digit. isalnum('a') is true
islower(c) Returns true if c is a lowercase islower('7') is false
letter. islower('a') is true
isupper(c) Returns true if c is an uppercase isupper('a') is false
letter. isupper('A') is true
isspace(c) Returns true if c is a whitespace isspace('\t') is true
character. isspace('A') is false
isprint(c) Returns true if c is a printable isprint(' ') is true
character including space ‘ ‘. isprint('A') is true
isgraph(c) Returns true if c is a printable isgraph(' ') is false
character excluding space ‘ ‘. isgraph('A') is true
ispunct(c) Returns true if c is a printable ispunct('*') is true
character other than a digit, ispunct(',') is true
letter, or space. ispunct('A') is false
iscntrl(c) Returns true if c is a control iscntrl('*') is false
character such as '\n', '\f', '\v', iscntrl('\n') is true
'\a', and '\b'. iscntrl('\f') is true
Function Description Example
tolower(c) Returns the lowercase equivalent of tolower('A') returns 'a'
c, if c is an uppercase letter. tolower('a') returns 'a'
Otherwise, return c itself. tolower('\t') returns '\t'
toupper(c) Returns the uppercase equivalent of toupper('A') returns 'A'
c, if c is a lowercase letter. toupper('a') returns 'A'
Otherwise, return c itself. toupper('\t') returns '\t'
§7.5 “struct” and Linked List
结构体类型复合数据类型包含多个并列成员
29
Struct Name{类型 变量名;
…… 类型 变量名; };
struct Student{ int std_no; char name[10]; int sex; int age; char dept[10];};
Variable of struct
30
int main(){ struct Student liu;
struct Student zhang= {20010346, ”Zhang” , 1, 18, ”Computer” };
liu.std_no = 0818976; strcpy(liu.name,“Liu Xiang”); cout<<liu.name<<“, “<<liu.std_no<<endl;}
struct Student{ int std_no; char name[10]; int sex; int age; char dept[10];};
struct Student stu1, stu2;
More Declarations
31
struct data { int day, month, year; } ; struct student { char name[20]; long num; struct data birthday; // 结构体嵌套 } ; struct student *pst;struct student st[2];
pst = new struct student;
Typedef
to assign alternative names to existing types
32
typedef int km_per_hour ; typedef int points ;
km_per_hour current_speed ; points high_score ; ...
struct var { int data1; char data2; };struct var a;
typedef struct var newtype;newtype b;
Case study
33
#include <iostream>#include <iomanip>using namespace std;struct data {
int day, month, year;};struct student{
char name[20];long num;struct data birthday;
// 结构体嵌套}; typedef struct student Std;
void swapStd(Std st[], int size){ struct student *pst; pst = new struct student;
for(int i =1; i<size; i+=2){ strcpy(pst->name,st[i-1].name); pst->num = st[i-1].num; pst->birthday.year = st[i-1].birthday.year; pst->birthday.month = st[i-1].birthday.month; pst->birthday.day = st[i-1].birthday.day; …… } delete pst;}
int main(){ Std st[2]; for(int i =0; i<2;i++){
cout<<"Input …:\n";cin>>st[i].name;cin>>st[i].num;cin>>st[i].birthday.year;…
} swapStd(st, 2); cout<<“…\n";}
Linked List
链表: a data structure consisting of a group of nodes which together represent a sequence.
逻辑关系用指针表示。 单链表、双向链表和循环链表等。
34
单链表
一个单链表结点,其结构类型分为两部分: 数据域:用来存储本身数据 链域或称为指针域:用来存储下一个结点地址
struct Node{ char ch; struct Node *next;}
Head Tail
链表的操作
查找
插入
删除 先查找 再删除
5
8
12
30Tail
Head
26
相等?
链表节点的访问都是通过指针!!
struct Node{ char ch; struct Node *next;}
建立链表 在链表的头部插入结点建立单链表
每个结点的存储空间是运行时系统根据需求而生成的 从空表开始,每读入一个数据,申请一个结点,然后插
在链表的头部∧
25 ∧455187629
76 18 25 ∧455
18 25 ∧455
25 ∧
25 ∧455
L
建立链表—头插入
38
LinkList Create_LinkList1( ){ LinkList lst=NULL ; /* 空表 */ LNode *s; int x; /* 设数据元素的类型为 int*/ cin>>x; while (x!=flag){ s=new LNode; s->data=x; s->next=lst; lst=s; cin>>x; } return lst;}
typedef struct node{ datatype data; struct node *next; } LNode , *LinkList;
建立链表—尾插入 保持节点生成顺序与链表顺序一致 每次是将新结点插入到链表的尾部 需加入一个指针 r 用来始终指向链表中的尾结点
39
29 76 12 365 89 ∧ L
•头指针 H=NULL ,尾指针 r=NULL;•将新结点插入到 r 所指结点的后面;•然后 r 指向新结点;
建立链表—尾插入
40
LinkList Creat_LinkList2( ){ LinkList L=NULL; Lnode *s,*r=NULL; int x; /* 设数据元素的类型为 int*/ cin>>x; while (x!=flag){ s=new LNode; s->data=x; if (L==NULL) L=s; /* 第一个结点的处理 */ else r->next=s; /* 其它结点的处理 */ r=s; /*r 指向新的尾结点 */ cin>>x; } if ( r!=NULL) r->next=NULL; /* 最后结点的指针域放空指针 */ return L;}
节点查找 get_Linklist(L, i) 算法思路:从链表的第一个元素结点起,判断当前
结点是否是第 i 个,直到表结束为止。 算法如下:
41
Lnode * get_LinkList(LinkList L, int i){ Lnode * p=L; int j=0; while (p->next !=NULL && j<i ) p=p->next; j++; if (j==i) return p; else return NULL; }
To search a key value?
节点插入—当前指针位置 p 指向插入位置, s 指向新节点 后插节点
将 *s 插入到 *p 的后面①s->next=p->next;
②p->next=s; // 两个指针的操作顺序不能交换。
42
p
s
×
①②
前插节点 ?
节点插入—位置序号
43
int Insert_LinkList( LinkList L, int i, datatype x){ /* 在单链表 L 的第 i 个位置上插入值为 x 的元素 */ Lnode * p,*s; p=get_LinkList(L,i-1); /* 查找第 i-1 个结点 */ if (p==NULL) cout<<“error\n”; else { s=new LNode; /* 申请、填装结点 */ s->data=x; s->next=p->next; /* 新结点插入在第 i-1 个结点的后面 */ p->next=s; } return 1; }
节点删除 设 p 指向单链表中某结点,删除 *p 。
首先要找到 *p 的前驱结点 *q ,然后完成指针操作。
44
pq
×
q->next=p->next;delete p;
int Del_LinkList(LinkList L , int i) { /* 删除单链表 L 上的第 i 个数据结点 */ LinkList p,s; p=get_LinkList(L,i-1); /* 查找第 i-1 个结点 */ if (p==NULL) { cout<<“ 第 i-1 个结点不存在 \n”; return -1; } if (p->next==NULL){ cout<<“ 第 i 个结点不存在 \n”; return 0; } else{ s=p->next; /*s 指向第 i 个结点 */ p->next=s->next; /* 从链表中删除 */ delete s; /* 释放 *s */ return 1; }}
Notes
在单链表上插入、删除一个结点,必须知道其前驱结点。
单链表不具有按序号随机访问的特性,只能从头指针开始,一个个顺序进行访问。
查找及删除时,无需进行元素的移动操作。
46
§7.6 Function Pointer ( 函数指针 )
Entry address of function ( 入口地址 ) Address of the first instruction Represented by function name
Pointer of function Pointing to a function Containing the entry address of the function
Declaration of function pointer
Syntax
functionType ( *nameOfPointer )( ParameterList )
E.g. :
Pointing to functions with matching header: Same parameter list and return type E.g.
int max(int, int);int min(int,int);int (*p)(int, int);p = max; p = min;
int (*p1)(int);
Invocation via function pointer
Similar to invocation via function name Syntax: (*functionPointer)(acutualParameterList) ; *functionPointer(acutualParameterList)
另外一种格式 - 不推荐函数指针名 ( 实参表 ) ;
p =max;c = (*p)(a,b); c = max(a,b);
函数指针示例
This is the print stuff function.This is the print stuff function.The data to be listed is 6.28318The data to be listed is 13The data to be printed is 3.14159
int main(){float pi = (float) 3.14159;float two_pi = (float)2.0*pi;void (*function_pointer)(float);function_pointer = print_stuff;*function_pointer(pi);function_pointer = print_message;*function_pointer(two_pi);*function_pointer(13.0);function_pointer = print_float;*function_pointer(pi);return 0;
}
void print_stuff(float dtoi){ cout<<"This is the print stuff function.\n“;}void print_message(float ltd){cout<<"The data to be listed is "<<ltd<<endl;}void print_float(float dtp){cout<<"The data to be printed is "<<dtp<<endl;}
函数指针作参数 ( 函数回调)
实现函数地址传递常用与事件处理等
subF( int(*p1)(int), int(*p2)(int,int)){
int a,b,i,j;……a = (*p1)(i);b = (*p2)(i,j);……
}
int f1(int);
int f2(int, int);
int main(){……subF(f1,f2);……
}
52
Summary
Concept of pointer Declaring pointers Indirection Pointer vs. Array Pointer as parameter and return value C-string using pointer struct and linked lists Function pointer