C语言基础——指针

本文详细介绍了C语言中的指针概念,包括指针与地址的关系、指针与参数的交互、指针与数组的运用,特别是针对二维数组的指针操作。此外,还探讨了指针在函数参数传递中的重要作用,以及main函数中命令行参数的处理。文章最后讨论了复杂的声明方式,帮助读者理解C语言中指针和声明的复杂性。

指针和地址

指针存储变量在内存中的地址,比如c是一个字符串,那么p就是一个指针,存储c的内存地址,形象地理解p“指向”c
在这里插入图片描述
在对象名称前面加&,返回内存中对象的地址,适用于变量和数组,不适用于表达式、常量和register变量。

p = &c;

p现在就是一个指针,可以用*来表示。比如

int x = 1, y = 2, z[10];
int *ip; /* ip is a pointer to int */
ip = &x; /* ip now points to x */
y = *ip; /* y is now 1 */
*ip = 0; /* x is now 0 */
ip = &z[0]; /* ip now points to z[0] */

如果对*ip进行操作,那么被操作的就是它指向的对象。比如这里将x加1,

y = *ip + 1;

由于编译器是从右到左扫描的,所以如果对指针ip进行自增操作,++放在后面,需要用括号将指针括起来,否则就是ip自增。

++*ip
(*ip)++

函数也可以返回指针,类型加*

char *alloc(int n) /* return pointer to n characters */
{
	if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits*/
		allocp += n;
		return allocp - n; /* old p */
	} else /* not enough room */
		return 0;
}

指针之间可以进行减法,但不能进行加法运算,和其他类型可以进行任何形式的计算。

指针和参数

因为C语言是值传递,变量在传进函数后,无论函数对变量进行什么操作,都不会改变变量的值。比如这里进行交换操作就不行,最后x还是,y还是y。

void swap(int x, int y) /* WRONG */
{
	int temp;
	temp = x;
	x = y;
	y = temp;
}

如果要想改变x和y的值,就需要用到指针。

void swap(int *px, int *py) /* interchange *px and *py */
{
	int temp;
	temp = *px;
	*px = *py;
	*py = temp;
}

操作过程如下图
在这里插入图片描述

指针和数组

数组内特定索引的元素的内存地址也可以用指针存储,但要注意的是如果是*(指针+1)那么指向的是下一个元素的内存地址。

int a[10];
int *pa;
pa = &a[0];
*(pa+1) /*指向的是a[1]*/

如果是*(pa+2),那么就指向下下个数组的元素,即a[2]。如果是减1就是指向上一个。
在这里插入图片描述
如果不加*,那么就是对当前索引的元素进行操作。

pa+1; /*a[0]+1*/

像二分查找这样的算法,需要对指针进行操作,要么就需要用到减法,减的结果是索引之差,可以与另一个指针进行加法运算。

int *high = &tab[0]int *low = &tab[10];;
mid = low + high;//非法
mid = low + (high-low) / 2

数组名称不是变量,而是数组的内存地址,即数组的第一个元素的内存地址。比如这里pa就相当于pa = &a[0],pa2就相当于pa = &a[2]

pa = a;
pa2 = a+2;

不能对数组名称进行操作,比如a++;,这时非法的。

指针和二维数组

如果是存储二维数组的内存地址,那么需要一个数组。

char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };

数组name的每个元素都是指向字符串的内存地址,而不是字符串本身。
在这里插入图片描述
如果是二维数组,就需要指定单个数组的长度,而不是给予

char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };

main函数

main函数有两个参数来接受命令行传过来的数值,argc是命令行传过来的数值的个数,argv是传过来的字符串的指针数组。*argv[0]存储的是程序的内存地址,因此argc至少为1。

#include <stdio.h>

main(int argc, char *argv[])
{
	int i;
	for (i = 1; i < argc; i++)
	printf("%s%s", argv[i], (i < argc-1) ? " " : "");
	printf("\n");
	return 0;
}

在这里插入图片描述

复杂声明

第一行代码是函数,返回的是指向int类型的指针。第二行代码是指针,指向返回int类型的函数。

int *f(); 
int (*pf)();

声明只是负责告诉编译器这个变量的存在,而不负责分配内存。在定义时,即给变量赋值时,才会分配内存。

C语言中,声明的形式为TypeName+Declarator。int iint是int是TypeName,是Declarator。“()”(非函数声明中的“()”)具有最高的紧密度,其次才是函数和数组的“()”和“[]”,即编译时先将“()”内的代码看成一个整体。

复杂声明的形式为

dcl: optional *'s direct-dcl
direct-dcl name
	(dcl)
	direct-dcl()
	direct-dcl[optional size]

dcl是declaration的简写,一般就是带*的direct-dcl。direct-dcl是一个name,后面可以跟跟()或[optional size],也可以是(dcl)这种形式。

int (*pfa[])();pfa是一个name,是direct-dcl。pfa[]就是direct-dcl[optional size]这种形式,也是一个direct-dcl。*pfa[]前面加上了*是一个dcl。(*pfa[])可以被看成一个direct-dcl,即(dcl)这种形式,int (*pfa[])();就可以看成是T D1()这种形式,是一个dcl

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值