复习指针

一、指针基础

int c = 0;为例
变量三要素:变量名c0,和其在内存中的地址

指针即地址值

指针变量为专门存放指针(某个变量的地址)的变量
或:指针变量的值为另一个变量的地址。

指针的大小一般为4字节(sizeof(指针变量) == 4),64位编译器中则为8。

定义一个指针变量:int *pointer;
其中

  1. int 说明了指针变量的基类型
  2. * 为指针运算符,说明pointer的类型为指针
  3. pointer 为指针变量名

基类型:指针变量指向的变量的类型

int c = 76;    
int *pointer;    //定义名字为pointer的指针变量
pointer = &c;    //将变量c的地址赋值给指针变量pointer,称指针变量pointer指向了变量c

int *p1 = NULL指针变量赋初值,使之成为空指针。

& *运算符的优先级

从高到低分别为:

  • 后置++ --
  • 前置++ --, ! * &
  • 算数运算符
  • 关系运算符<= < >= > == !=
  • && ||
  • 赋值运算符=
    注意:(*pointer)++不等于*pointer++
    前者指*pointer的值加1,后者指*pointer使用后,地址加一,即指向下一个地址单位的存储的变量,具体加几个字节由pointer的基类型决定。

二、指针与数组

1.指针指向数组元素时与指向普通变量没有区别

2.与数组

int a[5] = {10, 11, 12, 13, 14};
cout<< a<<endl;      //0017F754
cout<<*a<<endl;      //10
cout<<&a[0]<<endl;   //0017F754
cout<<a[0];          //10

可以看出:
数组名代表数组首元素的地址,数组名相当于 (并不是)指向数组首元素的指针。因此,数组名不是变量,不能给数组名赋值。

若定义:数组int a[10], 指针int *pointer;
pointer = a;等价于pointer = *a[0];
数组访问:

  • pointer + i;等价于a + i;等价于&a[i];
  • *(pointer + i);等价于*(a+i);等价于a[i];

表示形式:pointer[i];等价于*(pointer + i);

注意:

  • a++是没有意义的,但是p++会引起p的变化
  • p可以指向数组之外的元素
  • 因此,指针做加减运算时一定注意有效范围

3.与二维数组

例:输入i, j,输出a[i][j]

int a[3][4] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23};
int (*p)[4], i, j;      //p指向一个“包含4个int型元素的一维数组”
p = a;
cin >> i >> j;
cout << setw(4) << *(*(p + i) + j);

因为p指向一个“包含4个int型元素的一维数组”
所以*(p + i)指向第i + 1个“包含4个int型元素的一维数组”
p + i等价于&a[i]
*(p + i)等价于a[i],即指向第i行
*(p + i) + j等价于a[i] + j,即指向第j列
** *(*(p + i) + j)便等价于a[i][j]**
根据c语言的规范,此处直接写p[i][j]也可以

三、指针与字符串

指向字符串的指针:
char a[10]; char *p; p = a;
字符串与数组的区别:字符串末尾一定为\0
字符串为双引号包含:"hello",系统会自动补\0。数组为大括号内{'h', 'e', 'l', 'l', 'l', '\0'}(不加\0的话就没有)。

与整形数组的区别:
打印指向字符串数组的指针,会打印整个字符串,而不是地址。
打印指向整形数组的指针,则会打印地址。

int a[5] = {1, 2, 3};
int *pa = a;
char b[6] = {'h', 'e', 'l', 'l', 'l', '\0'};
char *pb = b;
                    //同样是打印数组名或者指针
cout<<a<<endl;      //整形数组打印a的地址值
cout<<pa<<endl;     //打印a的地址值

cout<<b<<endl;      //字符串打印内容hello
cout<<pb<<endl;     //打印hello
char buffer[10] = "ABC";
char *pc;
pc = "hello";
cout<<pc<<endl;  //打印hello
pc++;
cout<<pc<<endl;  //打印ello
cout<<*pc<<endl;  //打印e
pc = buffer;    //实际是把buffer[]的首地址赋给了pc,因此pc也指向了这个字符串
cout<<pc;  //打印ABC

四、指向二维数组的指针

1.再谈指向一维数组的指针

p -> a[0]
则++p -> a[1]
基类型起作用

根据c语言规范,一个数组名,当它不作为&,sizeof,Alignof的操作数时,可以看作是指向数组首的指针变量。

a是一个数组名,则a可以看作指向首元素的指针,其基类型为a数组的类型。&a则是指向整个数组地址值,可以看作指向整个数组的指针,其基类型为大小、类型与a相同的数组。&a相当于把a的管辖范围上升了一级,从首元素的地址上升到了整个数组的地址。*a则可以把管辖范围下降一级,从首元素的地址下降到首元素的值。因此*(&a)相当于,先上升,再下降,最后结果即为:a。因此cout<<*(&a)打印的结果与cout<<a相同,都打印数组a首元素的地址值。

2.指向二维数组的指针

int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

二位数组a[3][4]包含三个元素:a[0],a[1],a[2],每一个元素都是包含四个整形元素的一维数组。
按级别:

名称 级别 含义
&a 最高 指向整个二维数组的指针
a 指向a[0]即第一个一维数组的指针
a[0] 指向第一个一维数组中第一个元素的指针
a[0][0] 最低 第一个一维数组中第一个元素的值

同时可以使用&*运算符对他们进行级别的提升和下降;

三条规律

  • 数组名相当于指向数组第一个元素的指针
  • &可以提升一个级别
  • *可以下降一个级别

五、指针与函数

1.指针做函数的参数

可以将数组名作为实参传递给函数的指针形参
多维数组名作函数实参

int maxvalue( int (*p)[4]);    //p[i][j]即可访问数组a内的内容
main函数里:
int a[3][4];

数组名也可以直接做形参。C++编译器会将形参数组名作为指针变量来处理。
int sum(int arr[][4]);int sum((*arr)[4]);等效。前者:arr[]是形参,会被解释为arr指针变量,[4]说明arr指向的是有4个int型元素的数组。

int sum(int array[], int n);    //合法,array被当作了指针变量这样能够改动main函数里变量的值,可能会导致未知的危险
int sum(const int array[], int n);  //合法,且函数内*array的值不能被更改

指向符号常量的指针const int *p。不能通过*p = 20来赋值,或者其他方式修改指向的内容,即使它指向的变量不是常量。

2.指针做函数的返回值

int *function(int x, int y);
注意,应返回全局变量或静态局部变量的地址,否则子函数结束后,内存被释放,这个地址就没有意义了

静态局部变量

在子函数中定义,定义方式为static int value1 = 10。函数执行完毕后,内存被释放,但是这个静态局部变量不会被释放,因此仍然可以被使用。假设函数执行完毕后value1 == 20;,下一次执行此函数时,虽然按理又要执行定义语句static int value1 = 10使value1变成10,实际value1的值仍未20,并不会被再次初始化
虽然子函数会被调用多次,但是静态局部变量的定义语句只会执行一次。

六、练习

1.计算矩阵边缘元素之和

输入:

1    //数据组数
4 4    //矩阵行数、列数
1 1 1 1
0 0 0 0
1 0 1 0
0 0 0 0
3 3
3 4 1
3 7 1
2 0 1

输出:

5
15

代码:

#include<stdio.h>
#include<iostream>

using namespace std;

int answer;

int compute()
{
    int m, n;
    cin >> m >> n;
    int answer = 0;
    for(int i = 0; i < m; ++i)
    {
        int *p = new int[n];
        for(int x = 0; x < n; ++x)cin>>*(p + x);
        if(i == 0 || i == m - 1)
        for(int j = 0; j < n; ++j)
        {
            answer += *(p + j);
        }
        else
        {
            answer = answer + *p + *(p + n - 1);
        }
    }
    return answer;
}

int main()
{
    int k = 0;
    cin >> k;
    int *p = new int[k];
    for(int i = 0; i < k; ++i)
    {
        *(p + i) = compute();
    }
    for(int i = 0; i < k; ++i)
    {
        cout<<*(p + i)<<endl;
    }
    return 0;
}

2.二维数组右上左下遍历

输入:

3 4    //矩阵行数列数
1 2 4 7
3 5 8 10
6 9 11 12

输出:

1
2
3
4
5
6
7
8
9
10
11
12

代码:

#include<stdio.h>
#include<iostream>

using namespace std;

int main()
{
    int row, col;
    cin>>row>>col;                      //row == 3, col == 4
    int *p = new int[col * row];
    for(int i = 0; i < row; ++i)
    {
        for(int j = 0; j < col; ++j)
        cin>>*(p + i * col + j);
    }
    for(int j = 0; j < col; ++j)
    {
        cout<<*(p + j)<<endl;
        for(int i = 1, k = j - 1; k >= 0 && i < row; --k, ++i)
        cout<<*(p + i * col + k)<<endl;
    }
    for(int i = 1; i <= row - 1; ++i)
    {
        cout<<*(p + i * col + col -1)<<endl;
        for(int j = col - 2, k = i + 1;j >= 0 && k < row;++k, --j)
        cout<<*(p + k * col + j)<<endl;
    }
    
    return 0;
}

3.文字排版

输入:

84  //单词数
One sweltering day, I was scooping ice cream into cones and told my four children they could "buy" a cone from me for a hug. Almost immediately, the kids lined up to make their purchases. The three youngest each gave me a quick hug, grabbed their cones and raced back outside. But when my teenage son at the end of the line finally got his turn to "buy" his ice cream, he gave me two hugs. "Keep the changes," he said with a smile. 

输出:

One sweltering day, I was scooping ice cream into cones and told my four
children they could "buy" a cone from me for a hug. Almost immediately, the kids
lined up to make their purchases. The three youngest each gave me a quick hug,
grabbed their cones and raced back outside. But when my teenage son at the end
of the line finally got his turn to "buy" his ice cream, he gave me two hugs.
"Keep the changes," he said with a smile.

代码:

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>

using namespace std;

int lengthOfstr(char *str)
{
    return strlen(str);
}

int main()
{
    char str[50];
    int num, lengthOfLine = 0;
    cin>>num;
    for(int i = 0; i < num; ++i)
    {
        cin>>str;
        if(i == 0)          //全文第一个单词 
        {
            cout<<str;
            lengthOfLine += strlen(str); 
        }
        else if(lengthOfLine + 1 + strlen(str) <= 80)   //不是第一个单词且输出这一个单词后行字符数没超过80 
        { 
            cout<<" "<<str;
            lengthOfLine = lengthOfLine + 1 + strlen(str); 
        }
        else if(lengthOfLine + 1 + strlen(str) > 80)    //不是第一个单词且输出这一个单词后行字符数将超过80
        {
            cout<<endl<<str;
            lengthOfLine = strlen(str); 
        }   
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,387评论 3 44
  • 前言:指针是 C语言一个重要概念,也是C 语言的一个重要特色。使程序简洁、紧凑、高效。指针乃是C之精华。 数据在内...
    潇湘候晨雪阅读 720评论 0 0
  • 指针 指针是什么 为了了解指针的概念,我们先来看一个小故事。话说福尔摩斯派华生到威尔爵士居住的城堡去取回一个重要的...
    去留无意hmy阅读 501评论 0 1
  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,662评论 0 33
  • 一个不小心,就被我给抹了... 我的心呐,万马奔腾的...
    0Karen0阅读 200评论 3 2