Coursera_北大_C_language_指针

指针:

变量的地址称为指向该变量的指针。

利用取地址运算符 & 可以获得变量的地址。
cout << &c << endl;就可以获得变量c的起始地址。
其中一个变量的指针占用四个字节 (VC++2013环境)

利用指针运算符 * 可以访问地址里的资源。
cout << *&c << endl;就可以访问&c地址里的内容。

指针变量:

存放指针的变量。(说了好像和没说一样)

定义指针变量:

int *pointer;

int表明指针变量的基类型。
基类型:指针变量指向的变量类型。
如:

int c = 76;
int *pointer;
pinter = &c;
//不能写成pointer = c;

其中c的类型为int型,所以指针pointer的基类型是int型。

反过来可以通过指针变量来访问它所指的变量的值。也是用指针运算符 * 实现的。

int c = 76;
int *pointer = &c;

*pointer可以当作变量c用。

如代码:

#include <iostream>
using namespace std;
int main() {
	int iCount = 18;
	int* iPtr = &iCount;
	*iPtr = 58;
	cout << iCount << endl;
	cout << iPtr << endl;
	cout << &iCount << endl;
	cout << *iPtr << endl;
	cout << &iPtr << endl;
	return 0;
}

结果为:
58
00BCFBF0
00BCFBF0
58
00BCFBE4

&*的优先级比算术运算符级别要高,和逻辑非,前置++ - - 的优先级同级,低于后置++ - -。

关于:*pointer++

int a = 0;
int *p2 = Null;
p2 = &a;
p2++;

因为指定了指针变量p2 的基类型 int ,所以经过此++操作之后,系统将会理解为p2跨过整个区域(增加四个字节,而不是一个),这也是为什么要定义指针的基类型。

数组与指针:

指针指向数组的某个元素,和指向一个变量没有任何区别。

对于程序

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

结果为
0017F754
10
0017F754
10

打印数组的第一个元素地址和打印数组的地址是一样的。数组名相当于指向数组第一个元素的指针。

所以可以:

int a[5] = {10,11,12,13,14};
int *p =NULL;
cout << a << endl;
p = a;
cout << p << endl;
cout << *p << endl;
cout << *p++ << endl;
cout << *p++ << endl;

第一个*p++,++的含义是先操作,再将p加上一个数(四个字节),所以最终的结果是:
00C5FCB4
00C5FCB4
10
10
11
最终指针p停留在a[2]

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

使用指针指向数组第一个元素时,需要注意:
a++ 没有意义,但是p++会引起p的变化,甚至可以指向数组元素以外的元素。(操作指针的时候要注意有效的范围)

字符串与指针:

指向数组的指针
int a[10]; int *p; p = a;

指向字符串的指针(变量)
char a[10]; char *p; p = a;

char c[6] = {'h','e','l','l','o','\0'};
char *pc = c;

cout << c << endl;
cout << pc << endl;

结果都是打印出 hello 这个字符串,
如果想打印出地址,代码应该为:

cout << static_cast<void*>(c) << endl;
cout << static_cast<void*>(pc) << endl;
char buffer[10] = "ABC";
char *pc;
pc = "hello";
//之前是不能这样赋值的,不能把一个字符串直接赋给某个数组。指针的话可以直接赋值。但是不能利用指针去修改它,因为它是一个常量。
cout << pc << endl;
pc++;
cout << pc << endl;
cout << *pc << endl; //打印的是那个指针数组的第一个值。
pc = buffer; //允许,因为相当于直接把一个指针赋值给另一个指针。
cout << pc;

结果为:
hello
ello
e
ABC

指针与二位数组:

首先:

a[4] = {1,2,3,4};
cout << a << endl;
cout << &a << endl;

第二行的a是指向数组首位元素的一个指针。
第三行是指向数组a的一个指针,管辖范围是整个数组。
但这两行的结果是一样的。

如果这时候cout << &a + 1 << endl;
将会跨过所有数组,(4个)。而不等于cout << a+1 << endl;

在数组a前面加一个&相当于将这个表达式的管辖范围上升了一级,同理,如果是加一个*,将会降一级。

二维数组和一维数组的规律是一样的。
如定义数组 a[3][4]就是相当于三个一维数组组成。这个二维数组的第一个元素是a[0](包含了四个整型的一维数组)。又因为a的含义是指向数组的第一个元素的指针,及a[0]。同样,a[0]的含义就是指向a[0][0]的一个指针。
比a更高级的量是 &a,这是指向整个二维数组的指针。
a 与 &a[0] 等价, a[0] 与&a[0][0]等价。

访问二位数组的元素 a[i][j]:
int (*p)[4] 指向包含4个int型元素的一维数组。其实就是指向一个指针。(个人理解)

int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4],i,j;

*(*(p+i)+j)
p:指向一个包含四个int型元素的一维数组。
p+i:第i+1个包含4个int型的一维数组的地址。等价于a[i]
*(p+i)+j 等价于a[i] + j,注意这个a[i]也是一个数组,等同于a[i][0]的地址。等同于&a[i][j]
所以 *(*(p+i)+j)就是 a[i][j]
*(*(p+i)+j) 也可以直接写成 p[i][j]

指针与函数:

指针做函数参数:

void rank(int *q1,int *q2)
{
	int temp;
	if (*q1 < *q2)
	{
		temp = *q1;
		*q1 = *q2;
		*q2 = temp;
	}
}

int main()
{
	int a,b,*p1,*p2;
	cin >> a >> b;
	p1 = &a; p2 = &b;
	rank(p1,p2);
	cout << a << " " << b << endl;
	return 0;
}

如果把指针用作函数的参数,如上代码。则定义函数rank会直接影响主函数中的a,b的值。(因为是指针是a,b的地址。)

int maxvalue ( int (*p)[4] )
{
	int max = p[0][0];
	for (int i = 0; i<3 ; i++){
		for (int j = 0; j<4 ; j++){
			if (p[i][j] > max)
				max = p[i][j];
		}
	}
	return max;
}

int main()
{
	int a[3][4] = {{1,3,5,7},{2,4,6,8},{10,11,12,13}};
	cout << "The max value is " << maxvalue(a);
	return 0;
}
		

如上,可以用 (*p)[4]用来指向一个二维数组。用来解决多维数组作为函数参数的情况。

同样,可以用数组名做形参。

int sum(int array[], int n)
{
	for (int i = 0; i<n-1 ; i++){
		*(array + 1) = *array + *(array+1);
		array++;
		}
	return *array;
}
int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,10};
	cout << sum(a,10);
	return 0;
}

C++编译器将形参数组名作为指针变量来处理。相当于我们定义了一个指向int类型的指针变量*array。
但这个函数会在执行过程中把原数组a也同时改变了。

限制指针的功能:

在上代码定义函数的参数中加个const。

int sum(const int array[], int n)
{ // 这时候这个程序就会出错,*(array + 1) 的*上会出现一个红色波浪线。因为它无法被改变。
	for (int i = 0; i<n-1 ; i++){
		*(array + 1) = *array + *(array+1);
		array++;
		}
	return *array;
}

array变成了一个指向符号常量的指针。这样就将array这个数组保护起来,不会被改变。

int main()
{
	const int a = 78; const int b = 28; int c = 18; const int *pi = &a;
	*pi = 59;// 不允许,*pi不能被重新赋值
	pi = &b; //可以,pi可以重新赋值。
	pi = &c; *pi = 88; // 前者可以,后者不允许。
	return 0;
}

不能通过*pi方式修改指向的值,但是可以改变指的地址。

返回指针值的函数:

int *function(int x, int y);

函数名前面变数函数的类型 “*”

int *get(int arr[][4],int n, int m)
{ // 也可以 int (*arr)[4] 来定义。
	int *pt;
	pt = *(arr + n - 1) + m - 1;
	return (pt);
}

void main(){
	int a[4][4] = {1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16};
	int *p;
	p = get(a,2,3);
	cout << *p << endl;
}

但有时会出问题。

比如在定义函数
int *getInt1(){
	int value1 = 20;
	return &value1;
}
主函数:
int *p;
p = getInt1();
cout << *p << endl;
定义函数结束后空间就被释放,如果再返回指针p,返回出来的东西就啥都不是了。

静态局部变量(static):
静态局部变量中的局部变量的值再函数调用结束后不消失而保留原值。及占用的存储单元不被释放。
定义方法为:static int a;

void function ()
{
	int a = 0;
	static int b = 0;
	a = a+1;
	b = b+1;
	cout << a << endl;
	cout << b << endl;
}
int main()
{
	for (int i = 0; i < 3; i++)
	{
		function();
		cout << endl;
	}
	return 0;
}
结果为:
1
1

1
2

1
3

在函数function中 static int b = 0;只被执行过一次,如果再次运行function,但是这个定义静态局部变量只被执行了一次。b在上一次的基础上进行操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值