C/C++指针

1、*的理解:*是一种操作,对指针类型的变量进行操作,对指定的内存地址进行读写

变量的地址理论上是整数,可以用int类型表示,为了突出强调它是一个内存地址,用了新的整数类型表示,即指针类型

char*:表示一个char型变量的地址

int*:表示一个int型变量的地址

XXX*表示XXX型变量的地址,XXX可以除了上面两种数据类型外可以是其它任何数据类型。XXX*作为一个整体使用。

①因为每次重新运行程序时,变量的地址是重新分配的,所以每次显示的地址都不一样。

第二句定义了一个int*的变量p,变量p的值为变量a的地址(读作:指针p指向了变量a的地址)

int*表示变量p是一个int类型的地址,p 表示变量a 的内存地址*p表示取出变量a对应地址的值。(换句话说:指针是一个变量,既可以用p表示也可以用其它字母表示,只不过这个变量存储的是一个地址,指向内存的一个存储单元)

因此*(p+1)和p+1区别就很容易理解:

*(p+1):由于地址前加了*,所以表示指针p所指向的内存地址单元的下一个内存地址单元中的

p+1:由于p表示地址,所以p+1依然 表示地址,指针p所指向的内存地址的下一个内存地址

②指针变量重新赋值

int a=10;
int b=11;
int* p=&a;
p=&b;

定义了指针类型后再次赋值地址只需要写出指针变量即可(p表示的是一个int型变量的地址,&b表示的也是地址)

另外不同类型的指针不能直接赋值,如下

int a=10;
int* p=&a;
double* q=p;

 p表示一个int型变量的地址,而左侧为double*,类型不同不能互相赋值。

注意第三句的写法,已定义的指针变量给新的指针类型。左边的q表示的是double类型的地址,右边表示int类型的地址,如果不是类型错误,赋值操作是可行的

 

 

③看清楚是指针变量相减还是指针内容相减

迷惑性很强

另外这里说明数组元素在内存中是相连存储

 

④const指针

int a=10;
const int* p=&a;
*p=11;        //内存不可写
int b=*p;     //内存可读

const的作用:封禁了星号操作的写内存功能,但是其它的算术操作(指针赋值,指针加减法)不受影响

 

2、&的理解

变量的地址是一个整数,可以用操作符&取得

&是一个取地址符,&a表示变量a的地址(自己之前理解错误,受scanf函数输入变量的影响)

scanf("%d",&a); 表示从键盘接收一个整数存储到内存中&a所指的地址,也就是变量a中。

①变量地址的分配

	int x = 10;
	printf("%d", &x);

运行程序时,每次输出的值都不相同,这里就证明了&x输出的是地址而不是值

每次输出的指针变量和&变量的地址都会不同

 

②&和*的理解

int x;

x = 10;

int *p;//说明了p为指针(又称指针变量),按书本意思p为int型变量的地址

p = &x;//p就指向x了,地址赋给地址

一旦p指向x,x就相当于*p。也就是说,x与*p是等效的,代表同一个值。

再如

long *np, a = 4;

double *dp, d = 21.3;

np = &a; //执行此句后,*np的值为4

dp = &d; //执行此句后,*dp的值为21.3

*dp += (*np)++;

printf("*np = %ld, *dp = %.lf", *np, *dp);//输出5和4+21.3

这里double输出用的%lf,long输出用的%ld

③赋值

第二句虽然是在地址赋值,但赋值给指针ptr后,指向的内容就a变量的值

   对比理解:

简单理解就是:指针指向地址中的内容,但是赋值的是地址

地址赋值指针内容(这是是错误的理解,第一句仍然是地址赋值地址,因为ptr是一个int型变量的地址,只是前面用的int* ptr定义的)

地址赋值指针变量(因为前已经定义,所以省略*吗?ptr本来就表示的地址,所以通过&b进行赋值时正确的,如果左边是*ptr(表示内存值)相反是不正确的),但是常数0不能直接赋值给指针变量,如下,

常数赋值指针内容

常数0给指针变量后,指针就变成了空指针。无法将新的值存入到内存中

 

3、指针自加运算

*it1++=*it2++:

运算顺序:先赋值*(it1)=*(it2),然后指针后移it1++,it2++,赋值带*号,自加不带*号

输出结果为abddcccd

注意初试化时,str、it1,it2都为abcdcccd

将it2除去c的字符赋值给it1的前四位,剩余四位没有改变。注意第二个while循环,当it2连续出现3个c时,it2会自加,直至指到最后一个元素d为止,由于d元素后面为空,所以it1中只被替换了前4个元素

特殊说明:若在return str;前面加一句*it1 = '\0';这样输出就是abdd

 

4、数组-指针

赋值

①将数组名直接赋值给指针内容(变量名)(两种赋值方式都可以吗?)

int a[5];

*p=a;//p指向数组的第一个元素的地址

②将数组直接赋值给指针变量

调用函数时,p指向数组a的第一个元素,但在for循环中,有p=b,又把b的地址赋予了p,使p指向b的第一个元素,此时p与a已无关了。最终输出结果为“ABCDE”

注意:这里是传入的指针p,不是传入的数组a,所以再调用子函数fun前后p指向的位置不同

 

③指针指向数组中的固定值:&和a+2(两种方法均可达到效果)

int a[4] = { 12, 16, 20, 30 };
	int* p =  _________________;  // 令p指向 a[2]

方法1:根据①,变量名赋值给指针可以知结果为:a+2 

有IDE自己还不尝试一下,主动,主动,主动!

方法2:直接取a[2]地址:int* p = &a[2]; // 令p指向 a[2]

第二句表示p指向 a[1],不要单单看成数组元素值赋值指针内容的关系,否则P[0]和p[1]不好理解。看做指针指向数组的关系

 

指针数组和指针字符串

①指针数组:大括号中有多个指针变量,每个指针指向不同内容

char*p1="hello";

char*p2="world";

char*p3="a piece of cake";

char*str[]={p1,p2,p3};

printf("%c",*(str[0]+1));

str[0] 为p1,p1指向的是"hello" p1指针+1 前进一位指向字符e。最后输出e,而不是输出hello

 

两种形式的区别:

int   *p[4];         //指针数组。  大括号中有4个指针的数组, 每个元素都是指向整型的指针。突出地址,突出指针 

int   (*p)[4];       //定义了一个指针(定义了一个指向具有6个元素的数组的指针)。 ()的优先级最高,所以*p成块,代表指针,因此是一个数组指针,代表一个指向具有6个元素的一维数组的指针。

 

5、字符串-指针

 

 

6、指针作为入口参数

①传递指针参数:实参为指针地址p,形参为*p

void sub(int *pb)

{

    *pb = 88; //执行这句的时候,需要将*pb替换成*pa,否则容易糊涂

}

int main(void)

{

    int x = 25;

    int *pa;

    pa = &x;  //指针pa指向变量x对应的地址

    sub(pa);  //注意此处调用的入口参数为pa,不是*pa,pa等于pb,将88存入x(注意存入的位置)

    printf("x = %d", x);

    return 0;

}

 

7、long型指针(long型指针加1,指针向后移动4位)

void main()

{

char *p="abcdefgh",*r;

long *q;

q=(long*)p;

q++;

r=(char*)q;

printf ("%s\n",r);

}

q++;执行后,q指向字符串的第5个元素’e’,因为q是long型指针变量,增1相当于将q往后移动4个字符的位置。(常规情况下,指针都是int和char)

 

8、安全使用指针

弄清两个问题:

1、指针指向那?

2、指向的那块内存是否可用?

一个指针指向变量、数组或者指向0,指向0的指针被定义为空指针

int a;
int* p=&a;//指向一个变量

int arr[4];
int*p=arr;//指向一个数组


int *p=0;//空指针

如果一个指针未赋值,那么这个指针就是指向了一个不确定的内存地址,这样未赋值的指针被称为野指针 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值