一、指针的定义及基本概念
指针在C语言中具有重要的作用,它可以用来访问和操作内存中的数据,是C语言中的一种强大的工具。指针实际上就是相应数据类型的内存地址,指针变量存储的是数据的内存地址。下面我们来看一个简单的示例:
#includeint main() { int a = 3, b = 4; int *pointer = &a; printf("%d,%d,%d\n",*pointer,a,b); //3,3,4 *pointer = 5; printf("%d,%d,%d\n",*pointer,a,b); //5,5,4 pointer = &b; printf("%d,%d,%d",*pointer,a,b); //4,5,4 return 0; }
在上面的代码中,我们定义了一个指向整型变量a的指针,并将其初始化为a的内存地址。之后我们打印了指针所指向的变量a的值(即3),然后我们通过指针修改了a的值,并打印了a和指针指向的值(即5)。然后我们将指针指向了变量b,再次打印指针指向的值,此时输出的是变量b的值,即4。
二、指针的运算
指针的运算包括指针的加减、指针的比较。指针的加减通常用于指向数组中的元素,可以实现数组元素的遍历。指针之间的比较可以用于判断指向的地址大小关系,在排序、查找算法中有很重要的作用。下面我们来看一个示例:
#includeint main() { int arr[5] = {1,2,3,4,5}; int *pointer = arr; printf("%d,%d,%d\n",*pointer,*(pointer+1),*(pointer+2)); //1,2,3 if(pointer 在上面的代码中,我们定义了一个包含5个整型元素的数组,然后我们将指针指向了数组的首地址。之后我们通过指针访问数组中的元素,输出了前三个元素的值。最后我们比较了指针和数组最后一个元素的地址大小关系。由于指针指向的是数组的首地址,而数组名代表的是数组的首地址,因此arr+4实际上表示的是数组最后一个元素的下一个地址,所以我们判断了指针是否小于arr+4,输出了提示信息。
三、指针与函数
指针在函数中也扮演着重要的角色,指针参数可以让函数直接操作传递的数据,同时也能将函数内部的操作结果传递给调用者。下面我们来看一个示例:
#includevoid swap(int *p1, int *p2) { int temp; temp = *p1; *p1 = *p2; *p2 = temp; } int main() { int a = 3, b = 4; printf("%d,%d\n",a,b); //3,4 swap(&a,&b); printf("%d,%d",a,b); //4,3 return 0; } 在上面的代码中,我们定义了一个swap函数,它接受两个整型指针参数,并通过交换两个指针所指向的值,完成了两个整型变量的交换。在主函数中,我们定义了两个变量a和b,并打印了它们的值,随后我们调用了swap函数,并传递了a和b的地址,完成了变量的交换。之后我们再次输出a和b的值,可以看到它们已经交换了。
四、指向指针的指针
指向指针的指针是C语言中最复杂的概念之一,当我们定义一个指向指针的指针时,它实际上就是二级指针。指向指针的指针通常用于动态内存分配以及函数参数传递等场合。下面我们来看一个示例:
#includeint main() { int a = 3, *p1 = &a, **p2 = &p1; printf("%d,%d,%d,%d\n",a,*p1,**p2,***p2); //3,3,3,3 ***p2 = 5; printf("%d,%d,%d,%d",a,*p1,**p2,***p2); //5,5,5,5 return 0; } 在上面的代码中,我们定义了一个整型变量a,并定义了一个指向a的指针p1。随后我们定义了一个指向p1的指针p2,并通过二级指针间接访问了变量a的值。之后我们通过三级指针修改了变量a的值,并打印了变量a、指针p1、指针p2以及三级指针指向的值,可以发现它们都变成了5。
五、指针的常见误区
指针虽然在C语言中具有重要的作用,但也有很多容易出错的地方。下面我们举几个常见误区:
1、未初始化的指针
#includeint main() { int *p; printf("%d",*p); //可能输出任意值,也可能导致程序崩溃 return 0; } 在上面的代码中,我们定义了一个指针p,但没有给它初始化。当我们通过指针访问变量时,由于指针未指向有效的内存地址,可能导致程序崩溃。
2、指针类型的不匹配
#includeint main() { int a = 3; float *p = &a; return 0; } 在上面的代码中,我们定义了一个整型变量a,然后我们定义了一个浮点型指针p,并将其初始化为a的地址。由于指针类型与变量类型不匹配,编译器会给出警告或错误。
3、指针的非法操作
#includeint main() { int arr[5] = {1,2,3,4,5}; int *p = arr; p += 6; //非法 return 0; } 在上面的代码中,我们定义了一个整型数组arr,然后我们定义了一个指针p,并将其初始化为数组的首地址。当我们对指针进行加减运算时,如果越界访问数组,就会产生非法操作。