C 指针初步认识(一)

CPU 处理的数据保存在内存中。而内存又是分成一个个单元,这些单元是顺序排列,每个单元都有一个称为内存地址的编号,对内粗数据的访问都是通过地址进行的。内存单元的编号叫做地址(Address),也称为指针(Pointer)。内存单元的指针和 内存单元的内容是两个不同的概念。对于一个内存单元来说,单元的地址(编号)即为指针,其中存放的数据才是该单元的内容。在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。

举例说明:

char C = 'K';

假设有字符变量C,给其赋值内容为 'K'(ASCII码为十进制数 75),C占用了011A号单元(地址通常用十六进数表示)。设有指针变量P,内容为011A,这种情况我们称为P指向变量C,或说P是指向变量C的指针。

1.png

一个指针是一个地址,是一个常量。一个指针变量却可以被赋予不同的指针值,是变量。针变量的值是一个地址,那么这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。

数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。

在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。 这也是引入“指针”概念的一个重要原因。

定义指针变量
一般形式类型说明符 *变量名;
*****表示这是一个指针变量,
变量名是一个合法的标识符,
类型说明符表示该指针变量所指向的变量的数据类型。

int *i; // 定义一个int 类型指针变量 i
char *c;// 定义一个char 类型指针变量 c
float *f;// 定义一个float 类型指针变量 f

需要注意:
一个指针变量只能指向同类型的变量,如 i 只能指向 int 变量,不能时而指向一个 float 变量,时而又指向一个 char 变量.

指针变量的引用

指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值(初始化)。未初始化的指针变量的值是垃圾值,没有意义。

指针相关的两个运算符:
&:取地址运算符
*:指针运算符(或称“间接访问” 运算符)

指针初始化

int a=10; // 定义一个 int 变量 a 
int *p=&a; // 定义一个 int 指针变量 p, 并且指向 a 的地址

或者

int a=10; // 定义一个 int 类型变量 a 并且赋值 10
int *p; // 定义一个 int 类型指针变量 p 
p=&a;  // 将 a 的地址赋值给 p 指针变量

注意: 上面 第三行,被赋值的指针变量前不能再加*说明符,如写为 * p=&a 是错误的。

常见的一些指针操作

int main(){
    int *max, *min,*tmp, a, b;
    scanf("%d %d",&a, &b);
    max = &a;
    min = &b;
    if(*max < *min){
        // 交换指针变量的值,tmp 为临时变量
        tmp = max;
        max = min;
        min = tmp;
    }
    printf("a=%d\nb=%d\n", a, b);
    printf("max=%d\nmin=%d\n", *max, *min);
    return 0;
}
22 122
a=22
b=122
max=122
min=22

Process returned 0 (0x0)   execution time : 6.454 s
Press any key to continue.

指针变量作为函数参数

输入两个整数,按大小顺序输出

#include <stdio.h>

// 交换两个数
void swap(int *p1, int *p2){
    int temp;  //临时变量
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

int main(){
    int a, b;
    int *pointer_1, *pointer_2;
    scanf("%d, %d",&a, &b);
    pointer_1 = &a;
    pointer_2 = &b;
    if(a<b){
        swap(pointer_1, pointer_2);
    }
    printf("\n%d, %d\n",a, b);

    return 0;
}

运行结果:

10, 21
21, 10

解释:

  1. swap是自定义函数,它的作用是交换两个变量(a和b)的值。swap函数的形参p1、p2是指针变量。

2)程序运行时,先执行main函数,输入a和b的值。然后将a和b的地址分别赋给指针变量pointer_1和pointer_2,即使pointer_1指向a,pointer_2指向b。

  1. 接着执行if语句,由于a<b,因此执行swap函数。注意实参pointer_1和pointer_2是指针变量,在函数调用时,将实参变量的值传递给形参变量。采取的依然是“值传递”方式。因此虚实结合后形参p1的值为&a,p2的值为&b。这时p1和pointer_1指向变量a,p2和pointer_2指向变量b。

  2. 接着执行执行swap函数的函数体使p1和p2的值互换,也就是使a和b的值互换。函数调用结束后,p1和p2不复存在(已释放)。

如果将 swap 函数 改成这样,运行看看结果是怎样,猜想为什么是这样的结果

void swap(int x,int y){
    int temp;
    temp=x;
    x=y;
    y=temp;
}

根据上面代码改造

#include <stdio.h>

// 交换两个数
void swap(int *p1,int *p2){
    int *p;
    p = p1;
    p1 = p2;
    p2 = p;
}

int main(){
    int a, b;
    int *pointer_1, *pointer_2;
    scanf("%d, %d",&a, &b);
    pointer_1 = &a;
    pointer_2 = &b;
    if(a<b){
        swap(pointer_1, pointer_2);
    }
    printf("\n%d, %d\n",a, b);

    return 0;
}

运行代码,看看结果怎样?

指针运算符

取地址运算符&:& 是单目运算符,其结合性为自右至左,功能是取变量的地址。
取内容运算符*:* 是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在 * 运算符之后跟的变量必须是指针变量。

需要注意: 指针运算符(*)和指针变量说明中的指针说明符(*)不是一回事。

int *p; // 指针说明,在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型 
int *p=&a; // 表示指针变量p取得了整型变量a的地址
printf("%d\n",*p); // 语句表示输出变量a的值。

把一个变量的地址赋予指向相同数据类型的指针变量

int a, *pa;
pa=&a;  //把整型变量a的地址赋予整型指针变量pa 

把一个指针变量的值赋予指向相同类型变量的另一个指针变量

int a, *pa=&a, *pb;
pb=pa;  //把a的地址赋予指针变量pb,也就是 pa, pb 都指向a的地址

把数组的首地址赋予指向数组的指针变量

int arr[15], *pa;
pa=arr; 
//数组名表示数组的首地址,可以赋予指向数组的指针变量pa
//也可以写成这样
pa = arr[0]; //数组第一个元素的地址也是整个数组的首地址

对于数组的加减运算
对于指向数组的指针变量,可以加上或减去一个整数n。
pa+n -- 往后移动 n 个位置
pa-n -- 往前移动 n 个位置
pa++ -- 往后移动 1 个位置
++pa -- 往后移动 1 个位置
pa-- -- 往前移动 1 个位置
--pa -- 往前移动 1 个位置
需要注意:
数组指针变量向前或向后移动一个位置和地址加1或减1在概念上是不同的。
因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。
如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。
而不是在原地址基础上加1。

举个例子

int arr[5],*pa;
pa=arr; //pa指向数组arr,也是指向arr[0]的地址
pa=pa+3; //pa 往后移动三个位置,即pa现在指向arr[3],即pa的值为&pa[3]

指针之间的运算

a. 两指针变量相减 -- 两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。
实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。
注意:两个指针变量不能进行加法运算。毫无实际意义。
b. 两指针变量进行关系运算
pointer1 == pointer2 表示 比较 pointer1 和 pointer2 指向同一数组元素
pointer1 > pointer2 表示 pf1处于高地址位置
pointer1 < pointer2 表示 pf2处于低地址位置
pointer == 0 表示 ponter 是空指针
pointer != 0 表示 pointer 不是空指针

指针运算例子

#include <stdio.h>
int main(){
    //pa、pb为整型指针变量
    int a=10, b=20, sum, product, *pa, *pb;
    pa = &a;  //给指针变量pa赋值,pa指向变量a
    pb = &b;  //给指针变量pb赋值,pb指向变量b
    sum = *pa + *pb;  //求a+b之和,*pa就是a,*pb就是b
    product = *pa * *pb;  //求a*b之积
    printf("a=%d\nb=%d\na+b=%d\na*b=%d\n", a, b, a+b, a*b);
    printf("s=%d\nt=%d\n", sum, product);
    return 0;
}

运行结果:

a=10
b=20
a+b=30
a*b=200
s=30
t=200
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,430评论 3 44
  • 指针 指针是什么 为了了解指针的概念,我们先来看一个小故事。话说福尔摩斯派华生到威尔爵士居住的城堡去取回一个重要的...
    去留无意hmy阅读 547评论 0 1
  • void* 类型指针:通用变体类型指针;可以不经转换,赋给其他指针,函数指针除外;malloc返回的就是void*...
    冰吉凌阅读 3,317评论 0 18
  • 用origin作图时发现没有在一个工程里opj。这时怎么办呢?可以合并两个opj文件。如下操作首先打开其中一个op...
    鸭梨山大哎阅读 9,565评论 0 0
  • 一个穗儿,从右拨到左,这才意识到自己真的毕业了,站在周奶奶面前瞬间泪目。好像昨天才刚刚从张征奶奶的新生研讨课上走出...
    请叫我黄姑娘阅读 207评论 0 0