指针&常量
1.常量及常量指针
1.1(1)在C++中常量可分为6种,它们是整型常量、实型常量、字符型常量、字符串常量、符号常量、逻辑型常量
(2)const在前,内容不能变;
const在后,指针不能变;
const* ,指针指向为常量;
*const ,指针本身为常量
1.2把*读作"pointer to",从右至左念:
(1)b是一个常量
const int b; /* b is a int const */
int const b; /* b is a const int */
(2)p是一个普通指针,指向一个常量
const int *p; /* p is a pointer to int const */
int const *p; /* p is a pointer to const int */
(3)p是一个常量指针,指向一个普通变量
int *const p; /* p is a const pointer to int */
(4)p是一个常量指针,指向一个常量
const int *const p; /* p is a const pointer to int const */
int const *const p; /* p is a const pointer to const int */
(5)具有相同类型的指针类型变量p与一维数组a,不能进行的操作是(D)
A****:** **数组名a类型为int \*,与指针变量p是相同类型**,可以进行赋值操作;
**B****:a[0]与\*p都是int 型**,可以进行赋值操作;
**C****:&a[0] 的类型为int \*,与指针变量p是相同类型**,可以进行赋值操作;
**D****: &a的类型为 int (\*) [n],即指向数组的指针,与指针变量p不是相同类型,因此无法进行赋值操作**
(6)
int main()
{
int i=10;
int j=1;
const int *p1;//(1)
int const *p2=&i; //(2)
p2=&j;//(3)
int *const p3=&i;//(4)
*p3=20;//(5)
*p2=30;//(6)
p3=&j;//(7)
return 0;
}
解析:const在前,内容不能变;
const在后,指针不能变;
const* ,指针指向为常量;
*const ,指针本身为常量
1)const int*p1:表示不能通过指针p1修改它指向的内存单元的值,但是p1本身可修改。
(2)int const*p2=&i:与p1相同,即不能修改p2指向的内存单元的值,但是可以修改p2使其指向其它的内存单元。这里p2指向了整型变量i
(3)p2=&j:修改p2,使其指向整型变量 j ,由(2)可知(3)没错。
(4)int *constp3=&i:p3本身是指向整型变量的常指针,即p3初始化后不能再指向其它的内存单元,但是可以修改p3指向的内存单元的值。这里p3指向了整型变量i。
(5)*p3=20:通过p3将变量i的值修改为2,由(4)可知(5)没错。
(6)*p2=30:通过p2修改它所指向的内存单元的值,由(2)可知(6)错误。
(7)p3=&j:修改p3,使其指向j,由(4)可知(7)错误。
2.指针&数组
1、int(*p)[4];------ptr为指向含4个元素的一维整形数组的指针变量(是指针)
2、int *p[4];-------定义指针数组p,它由4个指向整型数据的指针元素组成(是数组)
3、int(*)[4];--------实际上可以看作是一种数据类型。也就是第一个(int(*p)[4];)
int (*p)[4]: ()优先级高 *p 首先是一个指针,类型是int,后面的 [4]表明这是一个指向一维整型数组的指针
int *p[4]: []优先级高, p[4] 首先是一个数组,类型是 int * ,也就是这是一个存放4个整型指针的数组p
3.指针&字符串
(1)对char*p="Hello’; char p[]字符串数组的理解。
若char* p=“Hello”;实际上p是一个指针,指向的内容是字符串常量Hello,指向的内容是不可修改的!如果执行*p+1='F’操作是错误的!
因为p是指针,可以让p指向别的内容,如p=“china” 是正确的。
char p[]=“Hello”;实际上是一个字符串数组初始化的方式,字符串数组的有两种初始化方式,一种是这样的初始化,另外一种是列表初始化;
而p可以理解为是一个常量指针,p的值不可修改,如p++操作是错误的。
char a[10]=“china”;
char a[10],*p=a;p=“china”;
char *a;a=“china”;
char a[10],*p;p=a=“china”;
A.是最常见的一种初始化方式。
B.p是一个指针,一开始指向的是一个字符数组a,后改变p指向了字符常量"china"
C.a是一个指针,指向了字符常量”china’’,是正确的。但是如果定义**char a[10];a=“china”;**是错误的!这相当于是数组的复制,而在c中并不存在数组复制的内建方法!
**D.**明显是错误的。
(2)可以把 ptr当作一个整体,指向一个char 的字符串,然后注意下面这些情况:
1 2 3 4 | *ptr = arr[0] = “hello” (*ptr)[1] = arr[0][1] = ‘e’ (*ptr + 1) = arr[0][1:] = “ello” *(ptr + 1) = arr[1] = “world” |
---|---|
4.指针自加
· *p++ 先取指针p指向的值(数组第一个元素2),再将指针p自增1
· (*p)++ 先去指针p指向的值(数组第一个元素2),再将该值自增1(数组第一个元素变为3)
· *++p 先将指针p自增1(此时指向数组第二个元素), 操作再取出该值
· ++*p 先取指针p指向的值(数组第一个元素2),再将该值自增1(数组第一个元素变为3)
5.指针访问数组中元素
c2.a
(*p).a
p->a
例题:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void getmemory(char*p) {
p=(char *) malloc(100);
strcpy(p,"hello world");
}
int main( )
{
char *str=NULL;
getmemory(str);
printf("%s\n",str);
free(str);
return 0;
}
上述代码运行会出现错误,主要原因如下:
指针指向常量(如char*str=“aaaaa”)和NULL时,不能通过指针修改常量,因为常量本身就是只读的。
退一步来讲,getmemory函数中,p一开始跟str指向同一个位置,经过“ p=(char*) malloc(100);”这句话之后p已经指向了动态开辟的空间的首地址,“strcpy(p,“hello world”);”操作针对的是动态开辟的空间,而不是str指向的地址空间了,getmemory函数执行完成后p又自动释放了,所以getmemory函数对str指向的地址空间没有实际的操作。
综上可知,str指向的内容未发生变化,故输出NULL。
6.例题
6.1
下面程序的功能是从输入字符串中找出最长字符串,则下面程序哪行存在错误( )
#include "stdio.h"
#include "string.h"
#define N 10
int main()
{
char s[N][81], * t; //line:1
int j;//line:2
for (j=0; j<N; j++)//line:3
gets (s[j]);//line:4
t= *s;//line:5
for (j=1; j<N; j++)//line:6
if (strlen(t)<strlen(s[j]))//line:7
t=&s[j];//line:8
printf("strings is: %d, %s\n", strlen(t), t);//line:9
}
A line:1
B line:4
C line:6
D line:8
D,t=&s[j] 改为 t = s[j]
s[j]已经是char *类型了
其实二维数组名的数据类型就是type(*arrayName)[column],即一个二级指针,所以将一个二级指针赋值给一级指针需要对二级指针变量使用指针运算符;而s[j]就是相当于一个行指针是一个一级指针,所以将一个一级指针赋值给一级指针不用取地址运算符;**。
6.2
假设已经有定义“ const char*name=" chen " ;”,下面的语句中错误的是()?
A.name[3]='q';
B.name="lin";
C.name=new char[3];
D.name=new char('q');
答案A,name被定义指向常量的指针,所以它所指的内容不能改变,但指针本身的内容可以修改,而“ name [ 3 ]=’ q’;”修改了name所指的内容,是错误的。"name== “lin”,name=new char[5];”和"name=new char(‘q’) ”以不同的方法修改了常指针,都是正确的
6.3
1.2指针
#include<iostream>
using namespace std;
int main()
{
int a[3][2] = { 0 }, (*ptr)[2], i, j;
for (i = 0; i < 2; i++)
{
ptr = a + i;
scanf_s("%d", ptr);
ptr++;
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
printf("%2d", a[i][j]);
printf("\n");
}
return 0;
}
首先,第一个for循环只循环了2次,所以3没有读入。其次,第一次ptr=a+0表示指向数组a的第一行第一个元素,即a[0][0],所以 a[0][0]=1,ptr++,ptr指向下一行(注意,不是下一个),但是由于第二次循环时 ptr=a+1,ptr被覆盖了,所以,ptr++并没有用,所以ptr是指向数组a的第二行,所以 a[1][0]=2。
6.4
#include<iostream>
#include<string>
using namespace std;
int main(int argc, int argv[])
{
const char* p1 = "hello";
const char* p2 = "world";
const char* p3 = "a piece of cake";
const char* str[] = { p1, p2, p3 };
cout << sizeof(*str[0]) << " " << typeid(str[0]).name() << " " << *(str[0] + 1) << endl;//typeid是类型
cout << sizeof(*&str[0]) << " " << typeid(&str[0]).name() << " " << *(&str[0] + 1) << endl;
cout << sizeof(*str) << " " << typeid(str).name() << " " << *(str + 1) << endl;
cout << sizeof(*&str) << " " << typeid(&str).name() << " " << *(&str + 1) << endl;
return 0;
}
运行结果:
1 ``char` `* e
4 ``char` `* * world
4 ``char` `* [3] world
12 ``char` `* (*)[3] 00F7F734
能看懂这个你就知道了,这个地方+1的时候都是说步长,
步长就是说+1前面的这个对象 所指向的 数据类型的长度,
比如 &str[0]类型是``char` `* * 所指向的是``char` `*
长度是指针的长度(不同机器不同)