指针

2019-02-21  本文已影响0人  crj1998

指针的概念

指针就是把地址作为数据处理,用于

指针变量:存储地址的变量。
变量的指针:当变量A存储变量B的地址时,那么A就是B的指针。

定义指针变量要告诉编译器该变量中存放的是一个地址,同时也需要知道指针指向的单元的数据类型。故指针的定义为:

类型标识符   *指针变量;

如何让指针指向某一变量?
用地址运算符 & 解决。如表达式 &x 返回的是变量 x 的地址,则有intp = &x;
& 运算符后面不能跟常量或表达式。如 &2 是没有意义的,&(m * n + p )也是没有意义的。

如何通过指针变量处理和改变它所指向的单元的值?
用引用运算符 * 解决。如 *intp 表示的是 intp 指向的这个单元的内容。如:*intp = 5 等价于 x = 5
在对 intp 使用引用运算之前,必须先对 intp 赋值。

指针在使用前必须初始化,没有初始化的指针可能指向任意地址,对这些指针作操作可能会导致程序错误。
NULL是一个特殊指针值,称为空指针。它的值为0。它可被用来初始化一个指针,表示不指向任何地址。

指针运算和数组

数组名可以看成是常量指针,对一维数组来说,数组名是数组的起始地址,也就是第0个元素的地址,如执行了p=array,则p与array是等价的,对该指针可以进行任何有关数组下标的操作。
指针保存的是一个地址,地址是一个整型数,因此可以进行各种算术运算,但仅有加减运算是有意义的。

int a[10], *p;
p=a;
// solution1
for (int i=0; i<10; i++)
    cout << p[i];
// solution2
for (int i=0; i<10; ++i)
    cout << *(p+i);
// solution3
for (;p<a+10; ++p);
    cout << *p ;
// 下面这种不行,因为a是常量,不能++
for (int i=0; i<10; ++i)
{
    cout << *a ;
    ++a;
} 

动态内存分配

动态内存分配与回收

type *p;

运算符new用于进行内存分配:

运算符delete释放分配的内存:

动态分配的检查

new操作的结果是申请到的空间的地址;当系统空间用完时,new操作可能失败;new操作失败时,返回空指针。

//动态分配检查
int main()
{   int *p;
    p = new int;
    if(!p) {
        cout << "allocation failure\n"; 
        return 1;
    }
    // 或者使用assert宏
    // assert宏在标准头文件cassert中;
    //assert()有一个参数,表示断言为真的表达式,预处理器产生测试该断言的代码。如果断言不是真,则在发出一个错误消息后程序会终止。 
    // assert (p != 0);
    *p = 20;  cout << *p; 
    delete p; return 0;
} 

内存分配的进一步介绍

静态变量:对全局变量和静态变量,编译器为它们分配空间,这些空间在整个程序运行期间都存在
自动变量:函数内的局部变量空间是分配在系统的栈工作区。当函数被调用时,空间被分配;当函数执行结束后,空间被释放
动态变量:在程序执行过程中需要新的存储空间时,可用动态分配的方法向系统申请新的空间,当不再使用时用显式的方法还给系统。这部分空间是从被称为堆的内存区域分配。

字符串与指针

char *String;
String = “abcde”; 

字符串常量存储在内存中数据段的区域里;将存储字符串”abcde”的内存的首地址赋给指针变量String;不能将String作为strcpy或strcat的第一个参数。
可以通过下标读取字符串中的字符,但不可以通过下标变量赋值。
可以直接作为字符串操作函数的参数。但必须注意,如果该指针指向的是一个字符串常量时,则使用是受限的。如不能作为strcpy的第一个参数。

char *String, ss[ ] =“abcdef”; 
String  = ss;

将字符数组ss的起始地址存入String

char *String; 
String = new char[10]; 
strcpy(String, “abc”);

动态变量存储在堆工作区 ;将存储字符串”aaa”的内存的首地址赋给指针变量String。

指针与函数

指针作为函数参数

用指针作为参数可以在函数中修改主调程序的变量值,即实现变量传递。
例如交换值函数

void swap(int *a, int *b){
    int c;
    c=*a; *a= *b; *b=c;
} 

// 调用函数
swap(&x, &y);

利用指针参数作为输出

#include <iostream>
#include<math.h>
using namespace std;

int func(double a, double b, double c, double *x1, double *x2){
    double delt = b*b-4*a*c;
    if (delt>0){
        double sdelt = sqrt(delt);
        *x1 = (-b+sdelt)/(2*a);
        *x2 = (-b-sdelt)/(2*a);
        return 2;
    }
    else if(delt==0){
        *x1 = -b/(2*a);
        *x2=*x1;
        return 1;
    }
    else{
        return 0;
    }
}

int main()
{
    double px1,px2;
    int result = func(2, 4, 2, &px1, &px2);
    switch (result){
    case 0:
        cout<<"0 solve "<<endl;
        break;
    case 1:
        cout<<"1 solve "<<px1<<endl;
        break;
    case 2:
        cout<<"2 solves "<<px1<<","<<px2<<endl;
        break;
    }
    return 0;
}

数组名作为函数参数

数组传递的本质是地址传递,因此形参和实参可以使用数组名,也可以使用指针。
如果传递的是数组

type func(type arr[], int size);

如果传递的是普通的指针

type func(type *p, int size);

C++将数组名作为参数传递处理成指针的传递。

//利用分治法获得数组最大值和最小值    
#include <iostream>
#include<math.h>
using namespace std;

void func(int a[], int n,int *max_value, int *min_value){
    switch (n){
    case 1:
        *min_value = *max_value = a[0];
        return;

    case 2:
        if (a[0]>a[1]){
            *max_value = a[0];
            *min_value = a[1];
            return;
        }
        else{
            *max_value = a[1];
            *min_value = a[0];
            return;
        }
    default:
        int max1,min1,max2,min2;
        func(a, n/2, &max1, &min1);
        func(a+n/2, n-n/2, &max2, &min2);
        if (max1>max2){
            *max_value = max1;
        }
        else{
            *max_value = max2;
        }
        if (min1<min2){
            *min_value = min1;
        }
        else{
            *min_value = min2;
        }
        return;
    }
}

int main()
{
    int a[]={1,9,8,2,3,7,6,4,5,0};
    int in,ax;
    func(a, 10, &in, &ax);
    cout<<in<<", "<<ax;
    return 0;
}

返回指针的函数

当函数的返回值是指针时,返回地址对应的变量不能是局部变量。

//获取子字符串
#include <iostream>
#include<string.h>
#include<math.h>
using namespace std;

char *subString(char *s, int start, int end)
{
    int len = strlen(s);
    if (start < 0 || start >= len || end < 0 || end >= len || start > end) {
        cout << "起始或终止位置错" << endl;
        return NULL;
    }
    char *sub = new char[end - start + 2];
    strncpy(sub, s + start, end - start +1);
    sub[end - start +1] = '\0';
    return sub;
}


int main()
{
    char *s="hello, world!";
    char *ss;
    ss=subString(s, 1,3);
    cout<<ss;
    return 0;
}

引用与函数

引用的定义:给一个变量取一个别名,使一个内存单元可以通过不同的变量名来访问。

//j是i的别名,i与j是同一个内存单元。
int i;
int &j=i;  

引用使用的注意事项:

C++引入引用的主要目的就是将引用作为函数的参数。

指针参数
void swap(int *m, int *n)
{   int temp;
     temp=*m;
    *m=*n;  *n=temp;
}
调用:swap(&x, &y)

引用参数
void swap(int &m, int &n)
{   int temp;
    temp=m;
    m=n; n=temp;
}
调用:swap(x, y)

注意:实参必须是变量,而不能是一个表达式。
C++中,函数参数一般都采用引用传递,好处是减少函数调用时的开销。如果在函数内不许改变参数的值,则参数用const限定,对非const的参数,实际参数不能是常量或临时量。

返回引用的函数是将函数用于赋值运算符的左边,即作为左值。

#include <iostream>
#include<string.h>
#include<math.h>
using namespace std;

int &index(int a[], int n){
    return a[n];
}

int main()
{
    int a[]={1,2,3};
    index(a,1)=5;
    cout<<*(a+1);
    return 0;
}

指针数组与多级指针

指针数组

一个数组,如果他的元素均为指针,则称为指针数组。
一维指针数组的定义形式:

 类型名  *数组名[数组长度];

字符串可以用一个指向字符的指针表示,一组字符串可以用一个指向字符的指针数组来表示。
用二分法查找某一个城市在城市表中是否出现

int binarySearch(char *cityTable[], int lh, int rh, char *cityName){
    int mid, result;

    if (lh <= rh){
        mid =(lh+rh)/2;
        result= strcmp(cityTable[mid], cityName);
        if (result == 0){
            return mid;
        }
        else if (result > 0){
            return binarySearch(cityTable, lh, mid-1, cityName);
        }
        else{
            return binarySearch(cityTable, mid+1, rh,cityName);
        }
    }
    return -1; //没有找到
}

int main()
{
    char *string[10] = {"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii","jjj"};
    char tmp[10];
    while (cin >> tmp){
        cout << binarySearch(string, 0, 9, tmp) << endl;
    }
    return 0;
}

main函数参数

main函数有二个形式参数:int argc, char *argv[]
argc:参数的数目(包括命令名本身)
argv[]:指向每个参数的指针,是一个指向字符串的指针数组

int main(int argc, char *argv[]){
    ...
}

多级指针

指针指向的内容还是一个指针,称为多级指针。
如有定义:char *string[10];string是一个数组,数组元素可以通过指针来访问。如果p是指向数组string的某一个元素,那么p指向的内容是一个指向字符的指针,因此p就是一个多级指针。string也是一个多级指针,不过是一个常指针。

// 按顺序输出指针数组元素
int main()
{
    char *city[] = {"aaa", "bbb", "ccc", "ddd",  "eee"};
    char **p;
    for (p=city; p<city+5; ++p)
        cout << *p << endl;
    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读