二、指针变量
1. 什么是指针变量
指针变量的本质是存放地址的变量,变量用来表示逻辑。
整型变量表示整数,所以变量中存放整数。
浮点型变量表示小数,所以变量中存放小数。
指针变量表示地址,指针变量中存放地址。
我们研究变量的用法,主要研究的是数据的用法。整型变量的用法取决于整数。
所以指针变量的用法取决于地址。
2.什么是地址
现实生活中的地址有什么用?用来查找地点。
内存很大,内存以字节为单位对里面的空间进行编址。在内存中每个字节都有自己唯一的地址。
1byte(字节) ======== 8bit(二进制位)
当我们定义变量的时候,系统会在内存中为变量分配空间。
当一个变量占多字节时,以地址最小的字节的地址,作为整个变量的地址。
3. 地址的运算
地址能进行怎样的运算,指针变量就能进行怎样的运算!!!
地址只有两种运算:
1、地址偏移
+ - 没有* / %
#include <stdio.h>
int main()
{
char a;//定义char类型变量a,char类型占1字节
//%p是地址的格式符
printf("%p %p\n", &a, &a+1);//打印a的地址,和a的地址+1 差值是1
return 0;
}
每次运行的地址是不一样的,因为变量的地址是系统自动分配的,我们决定不了。但是差值一定是1
#include <stdio.h>
int main()
{
int a;//定义整型变量a, int类型占4字节
printf("%p %p\n", &a, &a+1);//差值是4
return 0;
}
重点:地址是有类型的!
不同类型的地址+1后,加的字节数不一样。不同类型的地址,在数据上看不出区别。
char类型变量,能得到char类型地址,+1加1字节。因为char类型占1字节。
int类型变量,能得到int类型的地址,+1加4个字节。因为int类型占4字节。
int类型地址,+10,加10*4就是40字节。
2、间接运算
* 单目运算(一元运算) 乘法* 是二元运算
1. 间接运算只能对地址运算。
2. 间接运算的运算结果是地址对应的对象本身(itself)!间接运算得到的结果不是数值!!!
#include <stdio.h>
int main()
{
int a;
*(&a) = 10;//代码中的()可以不写,我写()的目的是让同学们看的更加醒目
/*
*(&a) = 10;
间接运算的优先级高,所以先算*(&a),对&a间接运算,得到的结果是变量a本身。
再进行赋值运算,所以赋值运算符的左值是变量a a = 10; 所以下面输入a的结果是10
*(&a) = 10;和a = 10是一样的。
*/
printf("%d\n", a);
return 0;
}
4. 定义指针变量
int *p;//定义指针变量p
/*
首先*说明p是指针变量,int说明指针变量中存放的地址是int类型的地址。
*/
在C和C++中,出现在声明语句中的符号,都不是运算符,而是用来表达标识符身份的符号!
这样的符号在C语言中有3个
[] 数组 ()函数 *指针变量
int a; //a是整型变量
int a[10]; //a是整型数组
int a(); //a是函数
int* a; //a是指针变量
1. 初始化
int a;
int *p = &a;//给p初始化,这里的*不是运算符,而是表达p是指针变量身份的符号。
2. 赋值
int a;
int *p;
p = &a;//对指针变量p赋值。
如果指针变量p中存放了变量a的地址,我们称p指向a。
下面的示例毫无意义,仅仅是为了演示语法。
#include <stdio.h>
int main()
{
int a;
int* p = &a;//使用a的地址给p赋值,p指向a
*p = 10;
/*
先算*,后算=
*p运算得到变量a本身,因为p中的数据是a的地址,对变量的运算就是对变量中的数据的运算。
所以=的左值是a, a = 10
*/
printf("%d\n", a);//10
return 0;
}
5.输出指针变量
%p (推荐) %x %#x
pointer指针
6.指针变量的意义
示例:
错误范例
#include <stdio.h>
void fun(int b);
int main()
{
int a;
fun(a);
printf("%d\n", a);//未知数
return 0;
}
void fun(int b)//使用main中的a初始化形参b
{
b = 10;//给形参b赋值和main中的实参a没有关系
}
使用指针变量的目的:在被调函数中使用主调函数中的变量,通过地址传递。
正确范例
void fun(int* b)//使用main中a的地址初始化形参b,b指向main中的a
{
*b = 10;//*b运算得到main中的a本身,所以这里是给main中的a赋值
}
int main()
{
int a;
fun(&a);
printf("%d\n", a);//10
return 0;
}
7.指针指向字符串常量:
使用字符串常量给指针变量赋值,是将字符串常量的首地址赋值给指针变量。
此时指针变量间接运算得到字符串常量中的第一个字符常量本身。
字符串常量在内存中是连续存放的。
char s1[] = “hello world”;//s1是字符类型的数组,使用字符串常量初始化s1
char* s2 = “hello world”; //s2是字符类型指针,存放了字符串常量的首地址,是h的地址。
s1[0] = 'a';//正确,数组的元素都是变量,可以对变量赋值
*s2 = 'a';//错误 s2中的数据是常量的地址,所以*s2得到常量本身,不能对常量赋值
32位(32个二进制位)操作系统,地址是4字节。
无论什么类型的地址,地址本身只占4字节。所以指针变量的大小就是4字节。
int* p;//没有被初始化的int类型指针变量
char* p2;//没有被初始化的char类型指针变量
char* p3 = "hello world";//被初始化的char类型指针变量
printf("%d %d %d\n", sizeof(p), sizeof(p2), sizeof(p3));// 4 4 4
指针定义编程示例1:
分别定义 int float 的变量,通过指针赋值,并输出变量的值和指针变量的值(地址)。 (熟悉指针)
一共定义4个变量,其中有两个是指针变量。
#include <stdio.h>
int main()
{
int a;
float b;
int* pa = &a;//初始化
float* pb = &b;
*pa = 10;
*pb = 12.3;
printf("%d %f %p %p\n", a, b, pa, pb);
return 0;
}
指针定义编程示例2:
定义函数,通过指针变量实现两个整数的交换。
int main()
{
int a = 10, b = 20;
swap(&a, &b);
printf("%d %d\n", a, b);//20, 10
return 0;
}
#include <stdio.h>
void swap(int* pa, int* pb);
int main()
{
int a = 10, b = 20;
swap(&a, &b);
printf("%d %d\n", a, b);
return 0;
}
/*
使用&a初始化形参pa,pa指向main中的a
使用&b初始化形参pb,pb指向main中的b
* */
void swap(int* pa, int* pb)
{
//*pa运算得到main中的a本身,*pb运算得到main中的b本身
int t = *pa;
*pa = *pb;
*pb = t;
}
平均值
#include <stdio.h>
void swap(int* pa, int* pb);
int main()
{
int a = 10, b = 20;
swap(&a, &b);
printf("%d %d\n", a, b);
return 0;
}
/*
使用&a初始化形参pa,pa指向main中的a
使用&b初始化形参pb,pb指向main中的b
* */
void swap(int* pa, int* pb)
{
//*pa运算得到main中的a本身,*pb运算得到main中的b本身
int t = *pa;
*pa = *pb;
*pb = t;
}
平均值