指针是地址的符号表示。它们使程序能够模拟按引用调用以及创建和操纵动态数据结构。它在C / C++中的一般声明具有以下格式:
句法:
datatype *var_name;
int *ptr; //ptr can point to an address which holds int data
如何使用指针?
- 定义一个指针变量
- 使用一元运算符(&)将变量的地址分配给指针,该运算运算符返回该变量的地址。
- 使用一元运算符(*)访问存储在地址中的值,该运算运算符返回位于其操作数指定的地址处的变量的值。
我们将数据类型与指针关联的原因是它知道数据存储在多少字节中。当我们增加一个指针时,我们将指针增加它所指向的数据类型的大小。
C
// C++ program to illustrate Pointers in C++
#include
void geeks()
{
int var = 20;
// declare pointer variable
int *ptr;
// note that data type of ptr and var must be same
ptr = &var;
// assign the address of a variable to a pointer
printf("Value at ptr = %p \n",ptr);
printf("Value at var = %d \n",var);
printf("Value at *ptr = %d \n", *ptr);
}
// Driver program
int main()
{
geeks();
}
C++
// C++ program to illustrate Pointers in C++
#include
using namespace std;
void geeks()
{
int var = 20;
//declare pointer variable
int *ptr;
//note that data type of ptr and var must be same
ptr = &var;
// assign the address of a variable to a pointer
cout << "Value at ptr = " << ptr << "\n";
cout << "Value at var = " << var << "\n";
cout << "Value at *ptr = " << *ptr << "\n";
}
//Driver program
int main()
{
geeks();
}
C
// C program to illustrate call-by-methods
#include
void geeks()
{
//Declare an array
int val[3] = { 5, 10, 20 };
//declare pointer variable
int *ptr;
//Assign the address of val[0] to ptr
// We can use ptr=&val[0];(both are same)
ptr = val ;
printf("Elements of the array are: ");
printf("%d %d %d", ptr[0], ptr[1], ptr[2]);
}
//Driver program
int main()
{
geeks();
}
C++
// C++ program to illustrate Array Name as Pointers in C++
#include
using namespace std;
void geeks()
{
//Declare an array
int val[3] = { 5, 10, 20 };
//declare pointer variable
int *ptr;
//Assign the address of val[0] to ptr
// We can use ptr=&val[0];(both are same)
ptr = val ;
cout << "Elements of the array are: ";
cout << ptr[0] << " " << ptr[1] << " " << ptr[2];
}
//Driver program
int main()
{
geeks();
}
输出:
Value at ptr = 0x7ffcb9e9ea4c
Value at var = 20
Value at *ptr = 20
参考和指针
有3种方式将C++参数传递给函数:
- 按值致电
- 带有指针参数的按引用调用
- 通过引用调用带有引用参数
// C++ program to illustrate call-by-methods in C++
#include
using namespace std;
//Pass-by-Value
int square1(int n)
{
//Address of n in square1() is not the same as n1 in main()
cout << "address of n1 in square1(): " << &n << "\n";
// clone modified inside the function
n *= n;
return n;
}
//Pass-by-Reference with Pointer Arguments
void square2(int *n)
{
//Address of n in square2() is the same as n2 in main()
cout << "address of n2 in square2(): " << n << "\n";
// Explicit de-referencing to get the value pointed-to
*n *= *n;
}
//Pass-by-Reference with Reference Arguments
void square3(int &n)
{
//Address of n in square3() is the same as n3 in main()
cout << "address of n3 in square3(): " << &n << "\n";
// Implicit de-referencing (without '*')
n *= n;
}
void geeks()
{
//Call-by-Value
int n1=8;
cout << "address of n1 in main(): " << &n1 << "\n";
cout << "Square of n1: " << square1(n1) << "\n";
cout << "No change in n1: " << n1 << "\n";
//Call-by-Reference with Pointer Arguments
int n2=8;
cout << "address of n2 in main(): " << &n2 << "\n";
square2(&n2);
cout << "Square of n2: " << n2 << "\n";
cout << "Change reflected in n2: " << n2 << "\n";
//Call-by-Reference with Reference Arguments
int n3=8;
cout << "address of n3 in main(): " << &n3 << "\n";
square3(n3);
cout << "Square of n3: " << n3 << "\n";
cout << "Change reflected in n3: " << n3 << "\n";
}
//Driver program
int main()
{
geeks();
}
输出:
address of n1 in main(): 0x7ffcdb2b4a44
address of n1 in square1(): 0x7ffcdb2b4a2c
Square of n1: 64
No change in n1: 8
address of n2 in main(): 0x7ffcdb2b4a48
address of n2 in square2(): 0x7ffcdb2b4a48
Square of n2: 64
Change reflected in n2: 64
address of n3 in main(): 0x7ffcdb2b4a4c
address of n3 in square3(): 0x7ffcdb2b4a4c
Square of n3: 64
Change reflected in n3: 64
在C++中,默认情况下,参数按值传递,并且在调用的函数所做的更改不会反映在传递的变量中。所做的更改将由被调用函数制作成一个克隆。
如果希望直接修改原始副本(尤其是在传递巨大的对象或数组时)和/或避免克隆的开销,则可以使用传递引用。带引用参数的引用传递不需要任何笨拙的语法即可进行引用和解引用。
- C中的函数指针
- 指向函数的指针
数组名称作为指针
数组名称包含数组的第一个元素的地址,该地址的作用类似于常量指针。这意味着存储在数组名称中的地址不能更改。
例如,如果我们有一个名为val的数组,则val和&val [0]可以互换使用。
C
// C program to illustrate call-by-methods
#include
void geeks()
{
//Declare an array
int val[3] = { 5, 10, 20 };
//declare pointer variable
int *ptr;
//Assign the address of val[0] to ptr
// We can use ptr=&val[0];(both are same)
ptr = val ;
printf("Elements of the array are: ");
printf("%d %d %d", ptr[0], ptr[1], ptr[2]);
}
//Driver program
int main()
{
geeks();
}
C++
// C++ program to illustrate Array Name as Pointers in C++
#include
using namespace std;
void geeks()
{
//Declare an array
int val[3] = { 5, 10, 20 };
//declare pointer variable
int *ptr;
//Assign the address of val[0] to ptr
// We can use ptr=&val[0];(both are same)
ptr = val ;
cout << "Elements of the array are: ";
cout << ptr[0] << " " << ptr[1] << " " << ptr[2];
}
//Driver program
int main()
{
geeks();
}
Output:
Elements of the array are: 5 10 20
如果将指针ptr作为参数发送给函数,则可以类似的方式访问数组val。
指针与数组
指针表达式和指针算术
可以对以下指针执行一组有限的算术运算:
- 递增(++)
- 递减(—)
- 可以将一个整数添加到指针(+或+ =)
- 可以从指针中减去一个整数(–或-=)
- 两个指针之间的差异(p1-p2)
(注意:指针算术是没有意义的,除非在数组上执行。)
// C++ program to illustrate Pointer Arithmetic in C++
#include
using namespace std;
void geeks()
{
//Declare an array
int v[3] = {10, 100, 200};
//declare pointer variable
int *ptr;
//Assign the address of v[0] to ptr
ptr = v;
for (int i = 0; i < 3; i++)
{
cout << "Value at ptr = " << ptr << "\n";
cout << "Value at *ptr = " << *ptr << "\n";
// Increment pointer ptr by 1
ptr++;
}
}
//Driver program
int main()
{
geeks();
}
Output:
Value at ptr = 0x7fff9a9e7920
Value at *ptr = 10
Value at ptr = 0x7fff9a9e7924
Value at *ptr = 100
Value at ptr = 0x7fff9a9e7928
Value at *ptr = 200
高级指针符号
考虑二维数字数组的指针符号。考虑以下声明
int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };
通常,nums [i] [j]等于*(*(nums + i)+ j)
指针和字符串字面量
字符串字面量是包含以空字符结尾的字符序列的数组。字符串字面量是字符类型加终止符的数组,每个元素的类型均为const char(因为不能修改字符串字符)。
const char * ptr = "geek";
这将声明一个数组,其字面量表示形式为“ geek”,然后将指向其第一个元素的指针分配给ptr。如果我们假设“怪胎”存储在从地址1800开始的内存位置,则可以将先前的声明表示为:
作为指针和数组在表达式以相同的方式表现,因此ptr可以被用来访问字符串字面量的字符。例如:
char x = *(ptr+3);
char y = ptr[3];
在此,x和y都包含存储在1803(1800 + 3)处的k。
指向指针的指针
在C++中,我们可以创建指向一个指针的指针,该指针又可以指向数据或其他指针。该语法只需要在声明指针时对每个间接级别使用一元运算运算符(*)。
char a;
char *b;
char ** c;
a = ’g’;
b = &a;
c = &b;
这里b指向存储’g’的char,c指向指针b。
虚空指针
这是C++中可用的一种特殊类型的指针,表示没有类型。 void指针是指向没有类型的值的指针(因此,它的长度也不确定,并且解引用属性也不确定)。
这意味着空指针具有很大的灵活性,因为它可以指向任何数据类型。这种灵活性是有回报的。这些指针不能直接取消引用。在取消引用之前,必须先将它们转换为其他指向特定数据类型的指针类型。
// C++ program to illustrate Void Pointer in C++
#include
using namespace std;
void increase(void *data,int ptrsize)
{
if(ptrsize == sizeof(char))
{
char *ptrchar;
//Typecast data to a char pointer
ptrchar = (char*)data;
//Increase the char stored at *ptrchar by 1
(*ptrchar)++;
cout << "*data points to a char"<<"\n";
}
else if(ptrsize == sizeof(int))
{
int *ptrint;
//Typecast data to a int pointer
ptrint = (int*)data;
//Increase the int stored at *ptrchar by 1
(*ptrint)++;
cout << "*data points to an int"<<"\n";
}
}
void geek()
{
// Declare a character
char c='x';
// Declare an integer
int i=10;
//Call increase function using a char and int address respectively
increase(&c,sizeof(c));
cout << "The new value of c is: " << c <<"\n";
increase(&i,sizeof(i));
cout << "The new value of i is: " << i <<"\n";
}
//Driver program
int main()
{
geek();
}
Output:
*data points to a char
The new value of c is: y
*data points to an int
The new value of i is: 11
无效的指针
指针应指向有效地址,但不一定指向有效元素(如数组)。这些称为无效指针。未初始化的指针也是无效的指针。
int *ptr1;
int arr[10];
int *ptr2 = arr+20;
在这里,ptr1未初始化,因此它成为无效指针,而ptr2在arr的范围之外,因此它也成为无效指针。
(注意:无效的指针不一定会引发编译错误)
空指针
空指针是指向无处的指针,而不仅仅是无效地址。
以下是将指针分配为NULL的2种方法;
int *ptr1 = 0;
int *ptr2 = NULL;