9指针
指针:具有确定属性的地址
属性决定了以该地址为起始地址的存储空间(数据单元)大小以及可以存放什么类型的数据
指针变量:可以存放指针的变量
指针的定义
指针变量声明
int *myPtr;
说明了一个指向int类型的指针变量myPtr
int *myPtr1,i,*myPtr2, j;
可以说明指向任何数据类型的指针
指针变量声明时可以初始化为 0,NULL或某个地址(指针)0 或 NULL: 不指向任何数据单元 (推荐使用NULL)。
指针运算
& (一元运算,地址运算符) //注意&的其它用法
运算结果为操作数(“左值性质”,非register)的地址(是一个指向操作数的指针),如
int y = 5; int *yPtr; yPtr = &y; 使 yPtr 指向 y
* (一元运算,间接引用运算符,其操作数表达式的值必须是指针),如
int *yPtr,y;
yptr = &y;
*yptr = 7;
*yptr = *yptr + 7;
运算结果为操作数指向的数据单元(“左值性质”)
注意:
* 和 & 互为 逆运算,如
int *yptr,y;
yptr = &y;
*yptr = 7;
*yptr = *yptr + *&y;
*&*&y = *yptr + *&y;
示例:
#include <stdio.h>
int main( )
{ int n; /* n is an integer */
int *nPtr; /* nPtr is a pointer to an integer */
n = 7;
nPtr = &n; /* nPtr set to address of n */
printf( "The address of n is %p"
"\nThe value of nPtr is %p", &n, nPtr );
printf( "\n\nThe value of n is %d"
"\nThe value of *nPtr is %d", n, *nPtr );
printf( "\n\n&*aPtr = %p \n*&nPtr = %p\n",
&*nPtr, *&nPtr );
return 0;
}
指针的算术运算
1.指针变量可以自增/自减 (++ 或 --)
2.指针可以加/减一个整数( + 或 += ,- 或 -=)
3.同类型指针可以相减
一元运算符sizeof( )
1.操作数为变量名、类型名或常量
2.运算结果为操作数所需存储单元的字节数
特例:当操作数为数组名时,运算结果为该数组所需存储单元的总字节数
3.如 sizeof(int)、 sizeof(int *)均为4,
在声明 int myArray[10],*p=myArray;后 sizeof(myArray)为40、 sizeof(p)为4
5 个元素的 int 数组v
int v[5], * vPtr = v ; // vPtr 为3000
vPtr += 2; // 赋值后 vPtr 为3008
把 vPtr的值当作整数和 n *sizeof(int)相加,得到 vPtr + n 的实际值,其它情况同理
同类型指针相减
int v[5], * vPtr , * vPtr2;
vPtr = &v[0];
vPtr2 = &v[2];
// vPtr2 - vPtr 结果为 2.
把 vPtr2和vPtr的值当作整数相减后除以 sizeof(int)
指针的关系运算
同类型指针可以进行各种关系运算
可以判断指针是否为 0或NULL
如
int v[5], * vPtr , * vPtr2;
vPtr = &v[0];
vPtr2 = &v[2];
while( vPtr < vPtr2 )
vPtr++;
指针的赋值运算
1.同类型指针可以赋值(需满足“左值性质”)
2.不同类型的指针,赋值运算前必须对赋值运算符右边的指针表达式进行强制类型转换 (不是隐式)
如 int * nPtr;
float f=0.5,* fPtr= &f;
nPtr = (int *) fPtr;
3.特例:指向 void 的指针(类型 void *),一般指针,指向任何类型的数据
任何指针可以不用类型转换,直接赋值给void *类型的指针,
如 void * vPtr; float * fPtr;vPtr = fPtr;
注意:void *类型的指针不能被复引用
指针和数组的关系
1.数组名是指向该数组第一个元素的常量指针
2.指针可以做数组下标运算
如: int b[5], *bPtr;
bPtr = b; //等价于bPtr = &b[0];
*( bPtr + 2 )=5; //等价于b[2]=5;
//等价于*(b+2)=5;等价于bPtr[2]=5;
//等价于(b+2)[0]=5;等价于(bPtr+1)[1]=5;
注:C++编译器把形如指针表达式[下标表达式]的下标运算转化为表达式 *(指针表达式+下标表达式 )。特别要注意理解数组形参和多维数组下标运算的含义
数组元素可以是指针
如:int *array[10],i; array[5]=&i;
又如:char *suit[4] =
{"Hearts","Diamonds",
"Clubs", "Spades" };
字符串的值:指向该串第一个字符的指针
suit 的每个元素是一个字符(char)指针
字符串中的字符并没有存放在数组中,数组中存放的是指向字符串的指针
suit 数组的元素数目是固定的,但字符串的长度可以不相等
const 限定符
在声明变量或形式参数时使用,明确地说明哪些数据是不会改变的。声明变量时通常要给出初值,如 const int studNum = 100 ;
指向常量数据的非常量指针
int i, j, *q;
const int * p;
p = &j; // 允许
p = &i; // 允许
i = 10; // 允许
*P = 5 ; // 不允许
指向非常量数据的常量指针
int var1,var2 ;
int * const p = &var1 ;
*P = 5 ; // 允许
P = &var2 ; // 不允许
注:非常量数据的常量指针的初值有限制,如
const int var ;
int * const p = &var ; // 错误!
指向常量数据的常量指针
const int val = 10;
const int *const p = &val ;
*P = 5 ; // 不允许
或
int var ;
const int *const p = &var ;
*P = 5 ; // 不允许
var = 5 ; // 允许
用于限定函数形式参数,以保护实参
void output(const double * pd)
{ cout << *pd ; // 允许
*pd = 15.5 ; // 不允许!
}
或
void output(const double &d)
{ cout << d ; // 允许
d = 15.5 ; // 不允许!
}
常用字符串处理函数(库文件string.h)
函数原型:
int strlen(const char *s);
函数原型:
char* strcpy(char* dest,
const char* src);
函数原型:
char* strcat(char* dest,
const char* src);
函数原型:
int strcmp(const char* s1,
const char* s2);
函数原型:
char* strchr(const char* s, int c);
函数原型:
char* strrchr(const char* s, int c);
函数原型:
char* strstr(const char* s1,
const char* s2);
函数原型:
char *strtok(char *s, char *delim);
两种分配内存的方式:静态和动态
静态内存分配
通过变量声明实现。所用内存空间(的大小)在编译时决定
动态内存分配
1.通过调用malloc函数或利用运算符new实现。所用内存空间在程序运行时分配
2.和malloc函数对应的释放内存函数是free
3.和new对应的释放内存运算符是delete
4.有可能因为系统内存缺少导致动态内存分配失败
函数malloc的原型是:
void *malloc(unsigned size);
例如:
int *p=(int *) malloc ( sizeof ( int ) ); (*p )++;
int *score=(int *) malloc ( sizeof ( int ) * studNum );
if (score != NULL )
for ( int j = 0 ; j < studNum ; j++ ) cin >> score [ j ];
函数free的原型是:
void free(void *ptr);
如:free(p); free(score);
使用new运算符分配内存,如
int *p= new int ; (*p )++;
int * score= new int [ studNum ];
for ( int j = 0 ; j < studNum ; j++ )
cin >> score [ j ];
使用delete运算符释放内存,如
delete p ;
delete [ ] score ;
例子一:指针与引用
#include <iostream.h>
void swap(int *, int *);
int main()
{int x = 10, y = 20;
swap(&x, &y); // 传递x和y的地址
cout<<"x:"<< x <<" y:" << y << endl;
return 0;
}
void swap(int * a, int * b)
{int temp;
temp = *a;
*a = *b;
*b = temp;
}
例子二:指针实现冒泡排序
void bubbleSort(int *array, int size)
{void swap( int *, int * );
int pass, j;
for ( pass=0; pass<size-1; pass++ )
for ( j = 0; j < size-pass-1; j++ )
if ( array[j] < array[j+1] )
swap( &array[j], &array[j+1] );
}
void swap(int * a, int * b)
{int temp;
temp = *a; *a = *b; *b = temp;
}
例子三:动态分配实现整数排序
#include <stdlib.h>
#include <iostream.h>
void sortArray ( int [ ], int );
void displayArray( int [ ], int );
int main()
{ int * a;
int i, num;
// 输入要排序的整数的数目
cout << "Please enter the number of integers: ";
cin >> num;
// 动态分配数组,以保存输入的整数
a = new int [ num ];
if (a == NULL)
{ cout << "malloc error! exit." << endl;
return 1;
}
// 输入拟排序的整数
for ( i = 0; i < num; i ++ )
cin >> a[i];
// 调用函数sortArray对 num 个整数进行排序
sortArray ( a, num );
// 输出a排序后的结果
cout << "After sorting:" << endl;
for (i = 0; i < num; i ++ )
cout << a[i] << " ";
cout << endl ;
// 释放动态分配的空间
delete [ ] a ;
return 0;
}
void sortArray( int b[ ], int len )
{ for (int pass = 0; pass < len – 1 ; pass ++ )
for ( int i = pass + 1; i <= len – 1 ; i ++ )
if ( b[ pass ] > b[ i ] )
{ int hold; hold = b[ pass ];
b[ pass ] = b[ i ]; b[ i ] = hold; }
}