指针是地址的符号表示。它们使程序能够通过引用模拟调用,以及创建和操作动态数据结构。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 <stdio.h> 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 " ,ptr); printf ( "Value at var = %d " ,var); printf ( "Value at *ptr = %d " , *ptr); } // Driver program int main() { geeks(); } |
C++
// C++ program to illustrate Pointers in C++ #include <bits/stdc++.h> 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 << "" ; cout << "Value at var = " << var << "" ; cout << "Value at *ptr = " << *ptr << "" ; } //Driver program int main() { geeks(); } |
输出:
Value at ptr = 0x7ffcb9e9ea4c Value at var = 20 Value at *ptr = 20
参考和指针
将C++参数传递给函数有3种方法:
- 按价值呼叫
- 带指针参数的引用调用
- 带引用参数的引用调用
// C++ program to illustrate call-by-methods in C++ #include <bits/stdc++.h> 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 << "" ; // 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 << "" ; // 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 << "" ; // Implicit de-referencing (without '*') n *= n; } void geeks() { //Call-by-Value int n1=8; cout << "address of n1 in main(): " << &n1 << "" ; cout << "Square of n1: " << square1(n1) << "" ; cout << "No change in n1: " << n1 << "" ; //Call-by-Reference with Pointer Arguments int n2=8; cout << "address of n2 in main(): " << &n2 << "" ; square2(&n2); cout << "Square of n2: " << n2 << "" ; cout << "Change reflected in n2: " << n2 << "" ; //Call-by-Reference with Reference Arguments int n3=8; cout << "address of n3 in main(): " << &n3 << "" ; square3(n3); cout << "Square of n3: " << n3 << "" ; cout << "Change reflected in n3: " << n3 << "" ; } //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++中,默认参数由值传递,调用函数中的更改不会反映在传递的变量中。所做的更改将由被调用的函数生成克隆。 如果希望直接修改原始副本(尤其是在传递大型对象或数组时)和/或避免克隆的开销,我们使用按引用传递。带引用参数的按引用传递不需要任何笨拙的语法来进行引用和取消引用。
数组名作为指针
数组名包含数组的第一个元素的地址,它的作用类似于常量指针。这意味着,数组名中存储的地址不能更改。 例如,如果我们有一个名为val的数组 瓦尔 和 &val[0] 可以互换使用。
C
// C program to illustrate call-by-methods #include <stdio.h> 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 <bits/stdc++.h> 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 <bits/stdc++.h> 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 << "" ; cout << "Value at *ptr = " << *ptr << "" ; // 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)
指针和字符串文本
字符串文字是包含以null结尾的字符序列的数组。字符串文字是字符类型加终止空字符的数组,每个元素都是常量字符类型(因为字符串的字符不能修改)。
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”的字符,c指向指针b。
这是C++中可用的一种特殊类型的指针,它表示类型的缺失。void指针是指向一个没有类型的值(因此也是一个未确定长度和未确定解引用属性)的指针。 这意味着void指针具有很大的灵活性,因为它可以指向任何数据类型。这种灵活性是有回报的。这些指针不能直接取消引用。在解引用之前,必须首先将它们转换为指向具体数据类型的其他指针类型。
// C++ program to illustrate Void Pointer in C++ #include <bits/stdc++.h> 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" << "" ; } 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" << "" ; } } 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 << "" ; increase(&i, sizeof (i)); cout << "The new value of i is: " << i << "" ; } //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的两种方法;
int *ptr1 = 0;
int *ptr2 = NULL;
测验 – 指针基础 , 高级指针 参考: https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp4_PointerReference.html
本文由 Abhirav Kariya。 如果你喜欢GeekSforgeks并想贡献自己的力量,你也可以用write写一篇文章。极客。组织或邮寄你的文章进行评论-team@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。