(五十七)指针、数组、指针算数

对指针加1,加的是指针类型的字节数。

例如:

int*a[5];

a+1;

这个时候,由于int是4字节,因此实际上是地址的位置加4,也就是向右移动一个int字节的宽度。

减一刚好相反,是向左。

 

而*a+1; 是指针a所指的地址的变量+1,但是指针位置是不变的。

#include<iostream>

int main()
{
	using namespace std;
	int *a;
	int b[4] = { 1,2,3,4 };	//声明数组b,数值分别为1~10
	cout << "int b[4] = { 1,2,3,4 }" << endl << endl;
	cout << "b[0]= " << b[0] << endl;	//输出数组b的第一个元素
	//输出数组b的地址 b 和 &b 时,二者输出是一样的
	cout << endl;
	a = &b[0];	//将指针和数组的第一个元素的地址对齐
	cout << "a = &b[0];" << endl;
	cout << "*a = " << *a << endl;	//输出指针a的变量
	cout << "指针a的地址为:" << a << endl;	//输出指针a的值
	a = a + 1;	//指针a+1
	cout << "a = a+1;\n*a = " << *a << endl;	//指针a+1后,指针a的变量
	cout << "指针a的地址为:" << a << endl;	//输出指针a的值
	cout << "*(a+1) = " << *(a + 1) << endl;	//指针a+1后,输出(a+1)的变量,注意,这里只是输出a+1,但并没有a=a+1
	cout << "*a = " << *a << endl;	//说明,没有a=a+1时,指针a的位置是不变的。输出的结果依然是2,也是数组b的第二个元素
	cout << "指针a的地址为:" << a << endl;	//输出指针a的值
	a = a - 1;	//指针a-1
	cout << endl << "a = a - 1;" << endl;
	cout << "*a = " << *a << endl;	//指针a+1后再次a-1,指针a的变量
	cout << "指针a的地址为:" << a << endl;	//输出指针a的值
	cout << endl << "以下对数组b的地址 b 和 &b 进行操作" << endl;
	cout << "数组b的地址,\nb      = " << b << endl;	//输出数组b的地址
	cout << "&b     = " << &b << endl;	//&b也是数组b的地址
	cout << "b + 1  = " << b + 1 << endl;	//b+1是加的数组中一个元素的宽度,地址偏移数组一个元素的类型(int)的距离
	cout << "&b + 1 = " << &b + 1 << endl;	//&b+1是地址偏离了整个数组长度的宽度的距离
	system("pause");
	return 0;
}

输出:

int b[4] = { 1,2,3,4 }

b[0]= 1

a = &b[0];
*a = 1
指针a的地址为:0040FBA8
a = a+1;
*a = 2
指针a的地址为:0040FBAC
*(a+1) = 3
*a = 2
指针a的地址为:0040FBAC

a = a - 1;
*a = 1
指针a的地址为:0040FBA8

以下对数组b的地址 b 和 &b 进行操作
数组b的地址,
b      = 0040FBA8
&b     = 0040FBA8
b + 1  = 0040FBAC
&b + 1 = 0040FBB8
请按任意键继续. . .

备注:

①int a[4];后,a是一个指针,是4字节(int)的指针;而&a是面向数组a全部元素的一个指针(4字节*4个元素);

 

 

 

指针算数:

两个指针可以相减,如代码:

#include<iostream>

int main()
{
	using namespace std;
	int a[10];
	int *b, *c;
	b = &a[0];
	c = &a[5];
	cout << "指针c为&a[5],指针b为&a[0]。指针c-指针b: c - b = " << c - b << endl;
	system("pause");
	return 0;
}

输出结果为:

5

结论:

①指针相减的结果,相当于两个元素之间指针需要偏移的距离(5个int)。

 

 

对指针解除引用:

对指针解除引用,实际上就是显示指针(所指向)的值,运算符是*。

例如int *p; p是指针,*p就是对指针p解除引用。

 

另外一种对指针解除引用的方法就是数组表示法,即p[0],[0]表示指针当前地址的值。

 

不要对没有被初始化的指针解除引用。

 

 

delete指针:

指针初始化后可以delete 指针。例如

int *a = new int;

delete a;

这样是ok的。也可以给指针赋值后,删除指针。

 

 

数组和指针:

上代码:

#include<iostream>
#include<cstring>

int main()
{
	using namespace std;

	char *a, b[10] = { 'a','b' };	//声明指针a。再声明数组b为字符串ab
	a = b;	//将字符串b赋值给指针a

	cout <<"a = "<< a << endl;	//指针a输出字符串
	cout <<"b = "<< b << endl;	//数组b输出字符串
	cout <<"&a= "<< &a << endl;	//输出指针a的地址,这是储存指针a的内存地址
	cout <<"&b[0] ="<< &b[0] << endl;	//这行无法输出数组b的地址,不加&输出的是数组b的第一个元素,
		//但加了&,cout会从第一个字符输出到空字符为止——(但是不知道为什么)
	cout <<"&b= "<< &b << endl;	//输出数组b的地址,注意,和指针a的地址是不同的
	cout << (int*)a << endl;	//只有改为(int*)a才能输出指针a所输出的地址,如果是(char*)a将依然输出字符组
	cout << endl;
	a = "ffff";

	cout << "a = " << a << endl;	//指针a输出字符串
	cout << "b = " << b << endl;	//数组b输出字符串
	cout << "&a= " << &a << endl;	//输出指针a的地址,这是储存指针a的内存地址
	cout << "&b[0] =" << &b[0] << endl;	//这行无法输出数组b的地址,不加&输出的是数组b的第一个元素,
										//但加了&,cout会从第一个字符输出到空字符为止——(但是不知道为什么)
	cout << "&b= " << &b << endl;	//输出数组b的地址,注意,和指针a的地址是不同的

	cout << endl;

	int *c, d;
	d = 123;
	c = &d;
	cout <<"c = "<< c << endl;
	cout <<"d = "<< d << endl;
	cout <<"&c= "<< &c << endl;
	cout <<"&d= "<< &d << endl;
	cout << endl << "*c = 5" << endl;
	*c = 5;
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;
	cout << "&c= " << &c << endl;
	cout << "&d= " << &d << endl;

	cout << endl;

	system("pause");
	return 0;
}

输出:

a = ab
b = ab
&a= 0029F790
&b[0] =ab
&b= 0029F77C
0029F77C

a = ffff
b = ab
&a= 0029F790
&b[0] =ab
&b= 0029F77C

c = 0029F764
d = 123
&c= 0029F770
&d= 0029F764

*c = 5
c = 0029F764
d = 5
&c= 0029F770
&d= 0029F764

请按任意键继续. . .

①当给指针赋值数组的时候,如果输出指针,那么实际输出的是数组(但数组如果有数字可能乱码,字符串不会)

 

②如果要输出地址,则需要给数组前面加&,或者给指针前面加&,才能输出地址。但两个输出的地址不同,&a是储存指针a的地址,&b是数组b的地址。a由于输出的是字符串,所以无法输出地址。只有加了(int*)或者其他(类型名*)才能将其强制转换为内存地址,若是(char*)将依然输出字符串

 

③储存指针的内存地址和指针所表示的内存地址,是不同的,前者的内存地址储存的值 是 指针的内存地址。

 

④当指针表示字符串的时候,改变指针的值,只改变指针的值,不像指针表示内存地址时,将影响指针指向内存地址的值。具体见a="ffff";后的语句。

 

⑤字符串/数组的第一个元素的内存地址,将表示数组的内存地址。但不能用(int*)数组名[0]这样的,把(int*)改成(char*)也不行,会输出地址,但不是预期想要的地址。至于为什么,不知道。只能用(int*)数组名,或者&数组名,才能显示数组的地址。

 

⑥char*a;是指针,当被赋值为字符串时,输出a的时候输出的就是字符串。

前者:(一般是char*指针情况下)

	char a[] = "abc";
	char *b;
	b = a;
	cout << a << endl;

输出的为:abc

后者:

	string a = "abc";
	string *b;
	b = &a;
	cout << b << endl;

输出的为:0043FDFC是一个地址。

 

 

 

指针和字符串:

数组和指针的特殊关系,是可以扩展到C-风格的字符串的。

例如:

char a[10] = "abc";
cout << a << endl;

其中在第二行语句中,字符串a实际上是被cout认为是字符串a的地址,而cout的效果,实际上是读取内存地址,然后按顺序输出字符,直到遇见空字符(\0)为止,另外,空格\回车等并非空字符。——这也是为什么字符串最后要是空字符的原因。

 

当使用指针的时候,如在上面代码后面加上这两句代码:

	char *b;
	b = a;
<span style="white-space:pre">	</span>cout << b << endl;

b是一个指针,又因为a实际上也是一个地址,因此a才能被赋值给b,此时b被认为是字符串a的地址。

然而,当cout遇见b的时候,因为cout发现两件事①b是地址②b是char类型的指针。于是,输出的是字符串,至于原因,要看下一行。

 

在cout和C++的多数表达式中,char 数组名、char 指针以及用括号引起的字符串常量(比如"abc"),都被解释为字符串的第一个字符的地址。而输出的是字符串。只有当在之前加上 & 之后,才能显示出内存地址。

 

比较典型的如以下代码:

#include<iostream>
#include<cstring>

int main()
{
	using namespace std;

	char animal[20] = "bear";	//声明字符串animale为"bear"
	const char * bird = "wren";		//常量字符串bird为wren
	char * ps;	//对于char*类型的指针,cout是根据指针地址输出字符串,而不像比如int*类型或者string*类型的指针那样输出地址

	cout << animal << " and " << bird << endl;	//输出字符串animal和常量字符串bird
	cout << "输入一种动物:";
	cin >> animal;	//让用户输入字符串animal,覆写之前的bear

	ps = animal;	//由于ps是一个可变指针,animal是字符串,所以ps是字符串
	cout << "ps = : " << ps << "!\n";	//输出ps(ps是字符串)

	cout << "在使用strcpy():之前——strcpy(目标字符串,源字符串)是将字符串从一个位置复制到另外一个位置\n";
	cout << animal << " at " << (int*)animal << endl;	//第一个animal是输出字符串,第二个加了(int*)是强制转换,输出的是指针
	cout << ps << " at " << (int*)ps << endl;	//第一个ps是指针,第二个ps加(int*)是输出储存指针的指针

	ps = new char[strlen(animal) +1]; //new 一个char字符串,宽度是animal宽度+1

	//strcpy(ps, animal);	//这行命令编译出错,正常来说,应该是将animal的字符串复制到ps新的内存地址处
	ps = "ab";	//用自行赋值替代
	cout << "在使用strcpy()之后\n";
	cout << animal << " at " << (int*)animal << endl;		//animal的值和地址不变
	cout << ps << " at " << (int*)ps << endl;	//ps获得新值和新的地址
	//delete[] ps; 这行代码应该是要删除指针ps,但实际上出错了,不知道为什么?

	system("pause");
	return 0;
}

 

①在以上这个代码之中,对于char*类型的指针,cout输出的为字符串。只有之前加上 & 之后,输出的才不是字符串,而是地址——只不过是储存指针的地址,而非指针指向的地址。

 

②对于字符串而言,cout输出的是字符串(直到遇见空字符\0)为止。只有在字符串(数组)之前加上&,显示的才是字符串的地址。

 

③对于int*类型,或者其他类似的指针来说,cout输出的指针是地址,但char*类型的指针例外——似乎也只有char*类型的例外。

 

④在vs2015里面,strcpy(ps,animal)这行语句会提示不安全。——但是我也不知道怎么改。

 

⑤因为ps是指针,因此才能ps=new char[],这是给指针a一个新的内存地址,这个时候,指针a的地址为该地址,但是&a为储存指针a的内存地址,只有用强制转换如(int*)a,才能得出新地址是在哪里。

 

⑥char*,数组,字符串,以及字符串常量(比如char a[5]="abc";这样。字符串abc为字符串常量,被储存在内存的某个专门的区域),cout都理解为内存地址,输出的是字符串,而不是地址。只有加了&后,才根据具体情况输出地址,但不一定是字符串所在地址——比如指针指向该字符串,指针加&输出的是储存该指针的内存地址(而非指针指向的内存地址)。

 

⑦因为char*类型,一般被cout认为是地址但输出的字符串,因此如果想输出地址的话,需要用强制转换,比如转换为(int*)类型的指针,才能输出地址。

 

⑧因为某个不知道的原因,删除指针delete[]ps;时,提示出错了,不知道为什么。

 

⑨假如char*a="abc"; cout <<a<<endl;这个时候,指针a指向了字符串abc所在的内存地址,输出的是abc。假如之后加上代码a="def";cout<<a<<endl;这个时候,改变a并没有将abc所在内存地址的值改变,而是改变了指针a指向的内存地址,为字符串"def"所在的内存地址。

 

想改变char *a所指向内存地址的值的话,需要通过*a='d';*(a+1)='e';*(a+2)='f';

这样,把字符串“abc”所在内存地址的值,改为字符串def。

或者通过

cin>>a;

这样,将用户输入的值,直接覆写到指针a所指向内存地址的之上。

但是不能通过比如*a="def";这种形式,企图一次写多个字符到字符串之中。

不过或许可以通过strncpy(a,"字符串",字符串长度);这样的形式将字符串写入,但问题在于,我的vs2015提示这是不安全的,无法编译。

 

 

时间: 2024-09-17 10:31:54

(五十七)指针、数组、指针算数的相关文章

C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表本文由 arthinking 发表于315 天前 ⁄ itzhai.com原创文章 ⁄ C语言 ⁄ 评论数 3 ⁄ 被围观 1,775 views+   指针数组: 在一个数组中,如果它的元素全部都是指针

数组 指针-数组指针,指针数组 ,存储方式

问题描述 数组指针,指针数组 ,存储方式 (1) int i; char p[3] = {"妹"}; CString str; str.Format("%s, ",p); (2) char *pch[6]={"妹","妹","你","做","船","头"}; for(int i=0;i<6;i++) { CString str; str.Fo

C语言 指针数组 和 指向指针的指针

指针数组 指针数组是一种特殊的数组,这类数组存放的全部是同一数据类型的内存地址.指针数组的定义形式为:     数据类型 *数组名[长度]; 例如: const char *c[4] = { "China", "USA", "Rassia", "Japan" }; // 定义长度为 4 的常量字符型指针数组,将数组元素分别指向 4 个 字符串常量 int i;for (i = 0; i < 4; i++){    put

C语言 指针数组详解及示例代码_C 语言

如果一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组.指针数组的定义形式一般为: dataType *arrayName[length]; [ ]的优先级高于*,该定义形式应该理解为: dataType *(arrayName[length]); 括号里面说明arrayName是一个数组,包含了length个元素,括号外面说明每个元素的类型为dataType *. 除了每个元素的数据类型不同,指针数组和普通数组在其他方面都是一样的,下面是一个简单的例子: #include <stdi

简单分析C语言中指针数组与数组指针的区别_C 语言

首先来分别看一下,指针数组的一个小例子: #include <stdio.h> #include <string.h> int lookup_keyword(const char*key, const char* table[], const int size) { int ret = -1; int i = 0; for(i=0; i<size; i++) { if (strcmp(key, table[i]) == 0) { ret = i; break; } } ret

C语言 数组指针详解及示例代码_C 语言

数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element).数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存.以int arr[] = { 99, 15, 100, 888, 252 };为例,该数组在内存中的分布如下图所示: 定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素.在C语言中,我们将第 0 个元素的地址称为数组的首地址.以上面的数组为例,下图是 arr 的指向: 下面的例子演示了如何以指针的方

c语言-关于字符型指针数组的理解问题

问题描述 关于字符型指针数组的理解问题 #include<stdio.h> main() { char *name[]={"zhang","gou","xu","zheng","mao","zhao","li","bai","qing"}; printf("%s ",*name[1]); } 此时

二维数组-关于C语言的指针数组的问题

问题描述 关于C语言的指针数组的问题 老师说过 传递一个二维数组时 必须指定 第二维的 个数 才能正确索引 数组1维+1的位置 函数参数传递 都是写成这样 abc(int* array[10]) 但是看到main函数的 参数确是 int main(int argc, char* argv[], char* env[]) 这样写 能索引argv+1 的位置吗? 解决方案 当然可以,C语言是一种简陋和原始的语言,它简陋的程度对于用惯了高级编程语言的人来说匪夷所思,比如你完全可以越界访问数组,至于结果

c-定义一个指针数组,这个数组名也是字符常量么,但为什么可以被另外一个数组名赋值?

问题描述 定义一个指针数组,这个数组名也是字符常量么,但为什么可以被另外一个数组名赋值? 例如: int x[4][3] ={0}; int (* p)[3] ; //这里p是一个以指针为元素的数组的数组名吧... p = x ; //为什么可以执行这步操作 解决方案 如果是指针,就可以被赋值.int (*p)[3] 是定义一个指向数组的指针,所以能被改变初始值 . P 说白了,其实就是三个指针.而不是数组. 就像 int i[3] 中的 i[0],i[1],i[2]不一样,是可以被修改的. 如