指针数组:
#include <stdio.h>
int main()
{
int i;
//这里插入一个指针,如果没有指针必须要依靠二维数组,而且会导致输出的时候比较麻烦。
//指针指向这五个数组。 数组中每一个元素都是指针。
char *p1[5] = {
"We are the world!",
"Nothin'on you!",
"Look at me now!",
"我是中国人!",
"ÎÒÊÇÖйúÈË£¡",
};
for(i = 0; i < 5; i++)
{
printf("%s\n", p1[i]);
}
return 0;
}
数组指针:
#include <stdio.h>
int main()
{
/*
int (*p2)[5] = {1, 2, 3, 4, 5};
int i;
for (i = 0; i < 5; i++);
{
printf("%d\n", *(p2 + i));
}
*/
/*
int temp[5] = {1, 2, 3, 4, 5};
int (*p2)[5] = temp;
//这里的temp表示的是temp数组的第一个元素的地址
//(因为二者本来就是一样的,但是仅仅是值一样)
int i;
for (i = 0; i < 5; i++);
{
printf("%d\n", *(p2 + i));
}
*/
int temp[5] = {1, 2, 3, 4, 5};
int(*p2)[5] = &temp; //注意这里temp用了&
int i;
for (i = 0; i < 5; i++);
{
printf("%d\n", *(*p2 + i));
}
/*
因为有&,所以
1、p2为数组的地址的地址;
2、*p2为数组的地址;
3、*p2 + n为数组的第(n + 1)个元素的地址
4、*(*p2)为数组第一个元素的值,*(*p2 + n)为数组的第n个元素的值
*/
return 0;
}
二维数组与数组指针
#include <stdio.h>
int main()
{
int array[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
/*
int **p = array;
这里不能用,因为C语言不够智能,无法识别array数组的一个元素到底代表了多少字节。
*/
int(*p)[4] = array;
/*
int (*p)[3][4] = &array;
可以这样写,但是后面的p要进行再一次的解引用,变为*(*(*p + i) + j))
*/
int i, j;
//这里用到了数组指针,由于(*p)[4]代表了一维数组(4个字节),而4表示了一共有4列,所以每加上一个i就是跳转到了下一行。
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
printf("%2d", *(*(p + i) + j));
printf("\n");
}
return 0;
}
指针用于交换
/*
说起指针,相信很多人都不太了解,但是又想要去了解,却没有付诸实际行动。今天我就带领大家一起探秘指针的奥秘。花了一下午时间,晚上自习估计也在做这个。(还是不会,所以改了标题)
说起指针,很多人肯定会想到8上面的那个按键* ,为什么再加上一个字母就有了取地址等意思了呢?(注意:* 和输入的是连在一起的,例如int* float* 这都是合法的语法标识符,但是写法可能又变化比如int* p等等)
顾名思义,地址就是一个单位在内存条里面的存储位置。这个位置是一直存在的,不论是有没有单位去占用它的位置。(故输出时加上地址就会准确的输出地址,而这个地址我们看不懂,是一直比C还低级的语言)
交换是能体现指针的作用的最佳说明,如下:
*/
#include <stdio.h>
void swap_no(int a, int b);
void swap_yes(int* a, int* b);
int main()
{
int a = 5, b = 3;
printf("In main,互换前:a = %d, b = %d\n", a, b);
swap_no(a, b);
printf("In main,用指针互换前:a = %d, b = %d\n", a, b);
swap_yes(&a, &b); //因为此处用到了指针,所以要求a和b都应该进行取地址才能输入到指针里面
printf("加指针后,In main,互换后:a = %d, b = %d\n", a, b);
return 0;
}
void swap_no(int a, int b)
{
int temp;
printf("In swap_no,互换前:a = %d, b = %d\n", a, b);
temp = a;
a = b;
b = temp;
printf("In swap_no,互换后:a = %d, b = %d\n", a, b);
}
void swap_yes(int* a, int* b)
{
int temp;
printf("加指针后,In swap_yes,互换前:a = %d, b = %d\n", *a, *b);
temp = *a;
*a = *b;
*b = temp;
printf("加指针后,In swap_yes,互换前:a = %d, b = %d\n", *a, *b);
}
//如果不用指针那就只能达到交换函数里面的a, b 值的作用,而我们要求的是交换外层函数里面的a, b 值,所以只能通过交换地址来简洁的达到交换作用。
/*
结果如下:
In main,互换前:a = 5, b = 3
In swap_no,互换前:a = 5, b = 3
In swap_no,互换后:a = 3, b = 5
In main,用指针互换前:a = 5, b = 3
加指针后,In swap_yes,互换前:a = 5, b = 3
加指针后,In swap_yes,互换前:a = 3, b = 5
加指针后,In main,互换后:a = 3, b = 5
*/
引用类型
-
C语言中不能用
-
引用(&)是标识符的别名
-
定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象
-
例如:
int i, j;
int &ri = i; // 定义int引用ri,并初始化为变量i的引用。
j = 10;
ri = j; // 相当于i = j
- 一旦一个引用被初始化后,就不能改为指向其他对象
- 引用可以作为形参
#include <iostream>
using namespace std;
void swap(int &a, int &b);
// 引用a了,相当于a和x是一样的,这就是双向传递效果。
// 即直接对实参进行改变,而不是形参
void swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
}
int main(void)
{
int x = 5, y = 10;
swap(x, y);
cout << x << '\t' << y << endl;
return 0;
}
函数指针
//函数指针,和数组指针一样,指向函数的指针(下面的*fp)
//typedef int (*PTR_TO_FUN)(int, int);
//int calc(PTR_TO_FUN, int, int)
int add(int, int);
int sub(int, int);
int calc(int (*)(int, int), int, int);
int (*select(char))(int, int);
int add(int num1, int num2)
{
return num1 + num2;
}
int sub(int num1, int num2)
{
return num1 - num2;
}
int calc(int (*fp)(int, int), int num1, int num2)
{
return (*fp)(num1, num2);
}
//这里用的话见注释。
int (*select(char op))(int, int)
{
switch (op)
{
case '+':return add;
case '-':return sub;
}
}
#include <stdio.h>
int main()
{
printf("3 + 5 = %d\n", calc(add, 3, 5)); // 这里可以用(& add),更加清晰。
printf("3 - 5 = %d\n", calc(sub, 3, 5));
/*
这里可以这样写
int num1, num2;
char op;
int (*fp)(int, int);
printf("请输入一个式子(如3 + 5):");
scanf("%d%c%d", &num1, &op, &num2);
fp = select(op);
printf("%d %c %d = %d\n", num1, op, num2, calc(fp, num1, num2));
*/
return 0;
}
指针函数
说白了就是个函数
注意一点就是
不要返回局部变量的指针
补充一点,要是C语言中需要用到字符串,可以用指针来代表字符串的首字符的地址,然后即可找到完整的字符串。
某一次讲课的笔记
#include <stdio.h>
int main()
{
//今天要介绍指针
//一.指针的基本概念和用法
// 1.一级指针的基本概念和用法
// 2.二级指针的基本概念和用法
// 3.多级指针
//二.指针和数组的关系
// 1.指针和一维数组的关系
// 2.指针和二维数组的关系
// 3.数组指针和指针数组的关系
//三、指针和字符串的关系
//四、指针和函数的关系
// 函数指针
int a = 10, b = 20;
/*
a和b分别储存在哪里?
内存 -> 栈中(局部变量) -> &a, &b
&:取地址运算符,能够求出一个变量的存储地址
%d:十进制的方式打印地址
%p/%x:十六进制方式打印地址
*/
printf("a,b的地址分别为:%d, %d", &a, &b);
/*
打印这个地址和指针有什么关系
指针就是地址,不能赋值,不能改变
&a = 3214324(错误的,不能改变)
常量:在运算过程中,值不能改变的量(每一次运行,操作系统都会重新分配,比如地址每次都在改变)
变量:在运算过程中,值可以发生改变的量
&a,&b:指针常量
指针变量:
怎么定义一个指针变量
基本数据类型:
char, short, int, long, float, double
int* p;靠近int说明p是属于int*型,p是属于变量,*不属于变量名的一部分
*/
//int* p1, p2, p3, p4, p5; 全部定义的都是指针变量吗? 只有p1是指针变量,其余都是int型
//int* p1, * p2, * p3, * p4, * p5; 这个才是全部都是指针变量。
/*
指针变量和普通变量有什么区别
普通变量存数值,指针变量存地址
指针变量一定要进行初始化,只有初始化之后的指针变量才能使用。
如果没有明确的指向,请用NULL(空指针)赋值
已经有了明确的指向,那可以直接使用地址赋值。
*/
//int* pa = NULL; pa不知道指向哪里,可以看作是指向内存地址为0的地方
int* pa = &a;
printf("pa = %d\n", pa); //打印的是a的内存地址,*&a <=> a
/*
修改内存
*:解引用运算符,间接访问运算符
后面跟一个地址,能够直接通过地址获取这块内存
*/
//C语言修改常量,语法灵活(C++就不能)
const int c = 300; //C是一个常量
int* pc = &c; //在前面再加上一个const才能在C++上进行修改
*pc = 800;
printf("c = %d\n", c);
int m = 1, n = 2;
printf("sizeof(m = n) = %d, m = %d, m = %d\n", sizeof(m = n), m, n);
printf("m = %d, n = %d", m, n); //m, n分别是多少?为什么没有变?
//为什么是这样?
//sizeof不是函数、sizeof是运算符
//sizeof只会确定里面类型的大小,不会进行赋值运算。
return 0;
}
结果:
a,b的地址分别为:8059772, 8059760pa = 8059772
c = 800
sizeof(m = n) = 4, m = 1, m = 2
m = 1, n = 2
void指针
#include <stdio.h>
int main()
{
int num = 1024;
int* pi = #
char* ps = "fishc";
void* pv;
pv = pi;
printf("pi:%p, pv:%p\n", pi, pv);
//这里必须强制转化,因为在void指针下解引用是没有作用的
printf("*pv:%d\n", *(int *)pv);
//这里不能使用,因为pv是1024的指针,但是以字符类型输出就不对了。
//ps = (char *)pv;
pv = ps;
printf("ps:%p, pv:%p\n", ps, pv);
printf("*pv:%s\n", (char*)pv);
return 0;
}
NULL指针
#define NULL ((void *)0)
#include <stdio.h>
int main()
{
int* pi;
int* p2 = NULL;
printf("%d\n", pi);
printf("%d\n", p2);
/*
这里会报错
当你不清楚将指针初始化为什么地址时,请先请先将它初始化为NULL
在对指针进行解引用时,先检查该指针是否为NULL
优点:节约调试时间。
*/
return 0;
}
以下是C++
指向常量的指针
const指针
不能通过指向常量的指针改变所指对象的指,但指针本身可以改变,可以指向另外的对象。
int a;
const int *p1 = &a; // p1是指向常量的指针
int b;
p1 = &b; // 正确,p1本身的值可以改变
*p1 = 1; // 编译时出错,不能通过p1改变所指的对象
指针类型的常量
声明指针常量,则指针本身不能改变
int a;
int *const p2 = &a;
p2 = &b; // 错误,p2是指针常量,值不能改变
this指针
- 隐含于类的每一个非静态成员函数中。
- 指出成员函数所操作的对象。
–当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针。 - 例如Point类的getX函数中:
return x; 相当于 return this->x;