c/c++是系统编程语言,处于运行效率的考虑,提供了指针这样的机制可以直接操作内存。而指针本身其实是虚拟内容的地址,比如在一个32位的操作系统上,一个进程的虚拟地址空间为4g,虚拟地址从0x0到0xFFFFFFFF,这段中的任何一个值就是内存地址。
如果指着指向的内容是代码的话,那么指向的是这块代码的入口地址,这个指针就叫做函数指针,比如int (*pmain)(int argc, int argv)。
这种直接操作内存的方式有利有弊,坏处在于大部分程序员管理不好内存,经常会出现内存泄漏,访问异常内存地址等各种问题。
指针用法
下面通过一些例子,来了解一下关于指针,引用的用法。
#include <iostream>
#include "pointer.h"
// 自己定义了一个pointer.h的头文件,用“”, 在c/c++中,函数的引用调用必须再在函数的定义之前
// 一般都会自己定义一个头文件。如果没有指定头文件的路径,那么会在当前文件夹中中寻找pointer.h
// 如果pointer不是在一个文件中,则制定头文件的路径,或者通过makefile的方式定义路径
using namespace std;
int main(){
int x = 12345;
int *p = &x;
cout << "p = " << p << endl;
cout <<"int *p = &x , *p = " <<*p << endl;
// int *p,此处为定义一个p指针,在定义的时候*p的作用是表明变量p是一个指针,不是解引用,指针p指向的内容是变量x的地址
// p打印出来为一串地址,定义之后*的使用为对指针地址的解引用,该内容指向的是变量x的内容
changePointers(p);
// changePointers(&x);
cout << "changePointers(p), *p = " << *p << endl;
// 给函数传递的真正的参数叫做实参,修改地址指向的内容变为404,changePointers(p)和changePointers(&x)一样
int y = 789;
p = &y;
cout << "p = &y; *p = " << *p << endl;
// 将p指针指向的内容改变为y的地址,解引用指针后,指针地址中指向的内容为变量y的内容
int &ref = x;
ref = 101;
cout << "int &ref = x, x = " << x << endl;
cout << "int &ref = x, ref = " << ref << endl;
// 此处用法为ref是x的引用,即ref是x的别名,如果ref发生了变化,x也会发生变化
changeNoRef(ref);
cout << "changeNoRef(ref), ref = " << ref << endl;
changeRef(ref);
cout << "changeRef(ref), ref = " << ref << endl;
}
void changeNoRef(int ref){
ref = 202;
}
// 修改形参的值为202,但是该函数返回后,实参的值不会受到影响
void changeRef(int & ref){
ref = 303;
}
// 修改形参的值为303,该函数返回后,实参的值会被修改为303
void changePointers(int *pointer){
*pointer = 404;
}
// int *pointer表明形参是一个地址,在定义指针的时候,*不是为指针的解引用。
// 可以通过指针的方式修改实参的值,但是形参在使用的时候必须使用解指针引用符号*
// *pointer表示形参地址解引用后指向的内容被更改为404
结果为:
字符与字符串
字符串与指针的用法比较绕,尤其是const char* 与char const和char const也是面试的常见题目
#include <iostream>
using namespace std;
int main(){
string a = "abcd";
cout << "a = " << a << endl;
// string a代表字符串
char b = 'i';
cout << "b = " << b << endl;
// char b表示字符
char c[] = "efg";
cout << "c = " << c << endl;
// char c[]真正的实现为: char *c = (char *)malloc(n); 其中n为要开辟空间的大小
// c是数组对应着一块内存区域,其地址和大小在生命周期内不会被改变,只有数组的内容可以改变
// 和int[]数组不同,此处c可以直接将字符串打印出
cout << "sizeof c : " << sizeof(c) << endl;
a = c;
cout << "a = c, a = " << a << endl;
// string 可以与char c[]进行转化
const char *d = "efg";
cout << "d = " << d << endl;
// char *d定义了一个char类型的指针,指针中存放的地址,并不知道内存单元有多大,所以如果此时要改变数组中的内容用d[2] = ‘d’是非法的
// 注意,此处如果不加const,编译器是会报错的,const char *ptr 表示的是指向字符串常量的指针,不能修改指针指向的内容
char const *d2 = "hello";
cout << "d2 = " << d2 << endl;
// char const *ptr 与 const char *ptr等价
char *const d3 = c;
cout << "d3 = " << d3 << endl;
// 定义一个指向字符的指针常数,即指针是const,但是字符串的内容可以修改
d3[2] = 'x';
cout << "d3[2] = 'x', d3 = " << d3 << endl;
}
结果为:
关于数组与指针
与字符串不同,数组默认指向的是数组元素的首地址,必须要通过解引用的方式获得数组的元素。
#include <iostream>
using namespace std;
int main(){
int array_a[] = {1, 2, 3};
cout << "array_a = " << array_a << endl;
cout << "*array_a = " << *array_a << endl;
cout << "*(array_a+1) = " << *(array_a + 1) << endl;
}