指针的指针、字符串和指针、数组指针(详)
一、指针的指针
指针的指针,即指针的地址
定义了一个指针变量,指针变量本身占4个字节,指针变量也有地址编号
例:
int a=0x12345678;
假设a的地址为:0x0000 2000
int *p;
p=&a;
则p中存放的是a的地址编号为0x0000 2000
因为p也占4个字节,有自己的地址编号,即指针变量的地址,即指针的指针
假设p的地址编号为0x0000 3000,这个地址是指针p的地址
定义一个变量去存放p的地址编号,这个变量就是指针的指针
int **q;
q=&p;//q就保存了p的地址,也可以说q指向了p
则q里存放的就是0x00003000
p和q都是指针变量,都占4个字节,都是存放地址编号,只是类型不一样
#include<stdio.h>
void main()
{int a=0x12345678;int *p;int **q;int ***m;p=&a;printf("&a=%p\n",&a);printf("p=%p\n",p);q=&p;printf("&p=%p\n",&p);printf("q=%p\n",q);m=&q;printf("&q=%p\n",&q);printf("m=%p\n",m);printf("*p=%#x\n",*p);printf("**q=%#x\n",**q);printf("***m=%#x\n",***m);}
/*
&a=0xbf9bde30
p=0xbf9bde30
&p=0xbf9bde34
q=0xbf9bde34
&q=0xbf9bde38
m=0xbf9bde38
*p=0x12345678
**q=0x12345678
***m=0x12345678*/
二、字符串和指针
字符串的概念:
字符串就是’\0’结尾的若干的字符的集合:”hello”
字符串的地址:是第一个字符的地址,字符串”hello”的地址,其实就是字符串中’h’的地址,即我们可以定义一个变量保存字符串的地址:char *s=”hello”;
字符串的存储形式:数组、文字常量区、堆
1.字符串存在数组中
其实就是在内存(栈、静态全局区)中开辟了一段空间存放字符串。
char str[100]=”hello”;
定义了一个字符数组str,用来存放多个字符,并且用hello给str数组初始化,字符串”hello”,存放在str中
注意:普通全局数组,内存分配在静态全局区
普通局部数组,内存分配在栈区
静态数组(静态全局数组、静态局部数组),内存分配在静态全局区
2.字符串存放在文字常量区
在文字常量区开辟了一段空间存放字符串,将字符串的首地址赋给指针变量
char *str=”helloworld”;
定义了一个字符指针变量str,只能存放字符地址编号,
“helloworld”这个字符串中的字符不是存放在str指针变量中
str只是存放了字符’h’的地址编号,“helloworld”存放在字符常量区
3.字符串存放在堆区
使用malloc等函数在堆区申请空间,将字符串拷贝到堆区
char *str=(char *)malloc(100*sizeof(char));//动态申请了100个字节的存储空间
首地址给str赋值
strcpy(str,”helloworld”);//将字符串”helloworld”拷贝到str指向的内存中
字符串的可修改性:
字符串的内容是否可以被修改,取决于字符串存放在哪里
(1)存放在数组中的字符串的内容是可以修改的
char str[100]=”helloworld”;
str[0]=’y’;//正确的,可以修改
注:数组没有被const修饰(只要被const修饰的变量都不可以改)
(2)文字常量区里面的内容是不可以修改的
char *str=”helloworld”;
str[0]=’y’;//错误的,h是存放在文字常量区,不可修改
注:str指向文字常量区的时候,它所指向的内容不可以被修改
str是指针变量,可以指向别的地方,即可以给str重新赋值
(3)堆区的内容是可以修改的
char *str=(char*)malloc(100);
strcpy(str,”helloworld”);
*str=’y’//正确,堆区的内容可以被修改
注意:str指向堆区的时候,它所指向的内容可以被修改
str是指针变量,可以指向别的地方,即可以给str重新赋值
总结:
(1)字符串的内容是否可以被修改,取决于字符串存放在哪里
(2)str指向文字常量区的时候,内存里面的内容不可以被修改
(3)str指向数组(非const修饰)、堆区,它指向的内存里面的内容是可以被修改的
例1:
#include<stdio.h>
void main()
{char str[100]="hello world!!";printf("str=%s\n",str);str[0]='y';printf("str=%s\n",str); //str=hello world!!//str=yello world!!
} 例2:
#include<stdio.h>
void main()
{char *str="hello world!!";printf("str=%s\n",str);//str=hello world!!*str='y';printf("str=%s\n",str); //Segmentation fault (core dumped)//改不了,出现段错误
} 例3:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{char *str=(char*)malloc(100);strcpy(str,"helloworld!!");//str=helloworld!!printf("str=%s\n",str); *str='y';printf("str=%s\n",str); //str=yelloworld!!
}
字符串的初始化
1.字符数组初始化:
char buf[100]=”hello world”;
2.指针指向文字常量区,初始化
char *buf=”hello world”;
3.指向堆区、堆区存放字符串
不能一来就初始化,先给指针赋值,让指针指向堆区,再使用strcpy、scanf等方法把字符串拷贝到堆区
char *buf;
buf=(char *)malloc(100);
strcpy(buf,”helloworld”);
scanf(“%s”,buf);
字符串使用时赋值
1.字符数组:使用scanf或者strcpy
char buf[20]=”hello world”;
buf=”hellokitty”;错误,因为字符数组的名字是个常量,不能用等号给常量赋值
strcpy(buf,”hellokitty”);正确,数组的内容是可以被修改的
scanf(“%s”,buf);正确,数组的内容是可以被修改的
2.指针指向文字常量区
char *buf=”hello world”;
buf=”hellokitty”;正确,buf指向另外一个字符串
strcpy(buf,”hellokitty”);错误,buf指向的文字常量区,内容是只读的,不可修改的,不能通过指针区修改文字常量区的内容
3.指针指向堆区,堆区存放字符串
char *buf;
buf=(char *)malloc(100);
strcpy(buf,”helloworld”);
scanf(“%s”,buf);
字符串和指针总结
(1)指针可以指向文字常量区
1)指针指向的文字常量区的内容不可以修改
2)指针的指向是可以改变的,重新赋值,让它指别的地方
(2)指针指向堆区
1)指针指向的堆区的内容可以修改
2)指针的指向是可以改变的,重新赋值,让它指别的地方
(3)指针指向数组(非const修饰)
char buf[20]=”hello world”;
char *str=buf;
- 可以修改buf数组的内容
- 可以通过str修改str指向的内存的内容,即buf的内容
- 不能给buf赋值,是常量
- 可以str赋值,让它指向别处
三、数组指针
1.二位数组
二维数组,有行有列。二维数组可以看成由多个一维数组构成的,是多个一维数组的集合,可以认为二维数组的每个元素是一维数组
例:int a[3][5];
定义了一个3行5列的二维数组
可以认为二维数组a由3个一维数组构成,每个元素是一个一维数组(这个一维数组有五个元素)
思考:数组的名字是数组的首地址,即第0个元素的地址,是个常量,数组名字加1指向下一个元素。
二维数组a中,a+1指向下一个元素,即下一个一维数组,即下一行
一维数组a[10];---------->a是a[0]的地址即&a[0],a+1-------->&a[1];
二维数组a[3][5];-------->a是a[0]的地址即&a[0],a+1--------->&a[1];
a[3][5]={
{1,2,3,4,5},
{ 6,7,8,9,0},
{5,4,3,2,1}
}
2.数组指针的概念
本身是一个指针,指向一个数组,加1跳一个数组,即下一个数组
3.数组指针的定义方法
指向的数组的类型 (* 指针变量名) [元素个数]
int ( * a)[5];//定义了一个数组指针变量a,a指向的是整型的有5个元素的数组a+1往下指5个整型,跳过一个有5个元素的一维数组
void main()
{int a[3][5];//定义了一个3行5列的数组int (*p)[5];//定义了一个数组指针变量p,P+1跳一个有5个元素的整型数组printf("a=%p\n",a);//第0行的地址printf("a+1=%p\n",a+1);//第1行的地址,a与a+1差20个字节p=a;printf("p=%p\n",p);printf("p+1=%p\n",p+1);printf("&a[0]=%p\n",&a[0]);//第0行的地址printf("&a[1]=%p\n",&a[1]);//第1行的地址printf("&a[0][0]=%p\n",&a[0][0]);//第0行首元素地址printf("&a[0][0]+1=%p\n",&a[0][0]+1);//第0行第2个元素地址
}
数组指针的用法1
例子:
void fun(int(*p)[5])
{p[1][4]=10;
}
void main()
{int a[3][5]={ {1,2,3,4,5},{6,7,8,9,0},{0,0,0,0,0} };//定义了一个3行5列的数组//fun()int i,j;fun(a);for(i=0;i<3;i++){for(j=0;j<5;j++){ printf("%d ",a[i][j]);}printf("\n");}
}
4.各种数组指针的定义
(1)一维数组指针,加1后指向下个一维数组
int (*p)[5];
配合每行有5个int型元素的二维数组来用
int a[3][5]
int b[4][5]
int c[5][5]
int d[6][5]
...
p=a;
p=b;
p=c;
p=d; 都是可以的
(2)二维数组指针,加1后指向下个二维数组
int (*p)[4][5];
配合三维数组来用,三维数组中由若干个4行5列的二维数组构成的
int a[3][4][5]
int b[4][4][5]
int c[5][4][5]
int d[6][4][5]
...
p=a;
p=b;
p=c;
p=d; 都是可以的
void main()
{int a[3][4][5];printf("a=%p\n",a);printf("a+1=%p\n",a+1);//a和a+1地址编号相差80个字节int (*p)[4][5]; //验证了a+1跳一个4行5列的二维数组p=a;printf("p=%p\n",p);printf("p+1=%p\n",p+1);//p和p+1地址编号相差80个字节
}
(3)三维数组指针,加1后指向下一个三维数组
int(*p)[4][5][6]
配合四维数组使用
int a[8][4][5][6]
多维数组指针以此类推......
5.容易混淆的概念
指针数组:是个数组,有若干个相同类型的指针构成的集合
int *p[10];
数组p有10个int *类型的指针变量构成,分别是p[0]~p[9]
数组指针:是个指针,指向一个数组,加1跳一个数组
int (*p)[10];
p是个指针,是个数组指针,p加1指向下一个数组,跳10个整型
指针的指针:
int **p;//p是指针的指针
int *q;
p=&q;
6.数组名字取地址,变成了数组指针
一维数组名字取地址,变成了一维数组指针,即加1跳一个一维数组
int a[10];
a+1跳一个整型元素,即a[1]的地址;
a和a+1相差了一个元素,4个字节
&a就变成了一维数组指针,是int(*p)[10]类型
(&a)+1和&a相差一个数组即10个元素即40个字节
拓展:&有升级功能 *有降级功能 &*相遇抵消
void main()
{int a[10];printf("a=%p\n",a);//a[0]的地址即&a[0],a=0xbfc00de8;printf("a+1=%p\n",a+1);//&a[1],a+1=0xbfc00dec与a相差4个字节printf("&a=%p\n",&a);//int(*p)[10]类型的,&a=0xbfc00de8printf("&a+1=%p\n",&a+1);//数组指针加1,跳一个数组,即跳10个元素//即40个字节 &a+1=0xbfc00e10
}
总结:a是int *类型的指针,即a[0]的地址
&a变成了数组指针int(*p)[10]类型,加1跳10个元素的一维数组
注意:
在运行程序时,发现a和&a所代表的地址编号时一样的,即它们指向同一个存储单元,但是a和&a的指针类型不一样
void main()
{int a[4][5];printf("a=%p\n",a);//int (*p)[5]一维数组指针printf("a+1=%p\n",a+1);//与a相差多少个字节,5*4=20printf("&a=%p\n",&a);//int (*p)[4][5] 取地址后升级变成了二维数组指针printf("&a+1=%p\n",&a+1);//与&a相差多少个字节,4*5*4=80
}
/*a=0xbfd624e0
a+1=0xbfd624f4
&a=0xbfd624e0
&a+1=0xbfd62530*/
9.数组名字和指针变量的区别
int a[5];
int *p;
p=a;
相同点:a是数组的名字,是a[0]的地址,即p=a即p保存了a[0]的地址,即a和p都是指向的a[0],所以在引用数组元素的时候,a和p是等价的
引用数组元素回顾:
a[2]、*(a+2)、*(p+2)、p[2]都是对数组a中a[2]元素的引用
void main()
{int a[5]={0,1,2,3,4};int *p;p=a;printf("a[2]=%d\n",a[2]);printf("p[2]=%d\n",p[2]);printf("*(a+2)=%d\n",*(a+2));printf("*(p+2)=%d\n",*(p+2));
}
不同点:(1)a是常量,p是变量
可以用’=’给p赋值,不能用等号给a赋值
(2)对a取地址,和对p取地址不一样
因为a是数组的名字,对a取地址结果是数组指针int (*p)[5]类型
&a+1-->5*4=20字节
p是指针变量,所以对p取地址结果为指针的指针
为int **类型
&p+1---->4个字节
往后指向一个int *类型的指针
void main()
{int a[5];int *p;p=a;printf("a=%p\n",a);//a是int *类型的指针,即a[0]的地址printf("&a=%p\n",&a);//&a变成了数组指针int(*p)[5]类型printf("&a+1=%p\n",&a+1);//与&a相差5*4=20printf("p=%p\n",p);//p是int *类型的指针printf("&p=%p\n",&p); //int **类型printf("&p+1=%p\n",&p+1); //与&p相差4个字节
}
指针的指针、字符串和指针、数组指针(详)相关推荐
- html字符串转成数组,图文详解JavaScript中字符串转换为数组的方法
在前端开发中经常需要使用JavaScript,那你知道怎么将JS字符串转换为数组吗?这篇文章就和大家讲讲JS将字符串转换为数组的方法,感兴趣的朋友可以参考一下,希望可以帮助到你. 之前一篇文章已经给大 ...
- python指针参数_Python调用C++ 传数组指针参数
最近需要用到Python下调用C++程序,看了很多博客记录下最实用的一种方法. 很多的方法,需要在编译C++程序的时候给出Python的库.因为在程序里引用了"Python.h". ...
- 【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读)
相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...
- 指针数组、数组指针、数组的区别与联系
指针数组.数组指针.数组的区别与联系! 一:基本定义 1.指针数组 char *arr[4] = {"hello", "world", "shannx ...
- C语言程序设计 | 指针的进阶(一):字符指针、数组指针、指针数组、函数指针
指针的进阶(一)目录: 字符指针 数组指针和指针数组 函数指针 字符指针 在开始讲解这一章节之前,我们需要了解指针前面声明的类型的意义 类型 * 指针名 对于指针来说,我们在给指针进行声明时,我们声明 ...
- 【C语言进阶深度学习记录】二十八 数组指针与指针数组的分析
数组指针与指针数是非常重要的概念.面试中也是经常会被问到的 文章目录 1 数组的类型 1.1 定义数组的类型 2 数组指针 2.1 数组类型和数组指针的代码分析 3 指针数组 3.1 指针数组代码案例 ...
- 指针 数组指针 指针数组 函数指针等说明。
指针的概念 原文地址:http://www.cnblogs.com/ggjucheng/archive/2011/12/13/2286391.html 指针是一个特殊的变量,它里面存储的数值被解释成为 ...
- c++数组指针和指针数组详解
指针数组: 指针数组可以说成是"指针的数组",首先这个变量是一个数组,其次,"指针"修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占 ...
- C语言数组指针(指向数组的指针)详解
数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element).数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存.以int arr[] = { 99, ...
- 深入浅出C语言:(三)C 语言数组指针(指向数组的指针)
目录 一.C 语言数组指针(指向数组的指针) 二.C 语言字符串指针(指向字符串的指针) 三.C 语言指针数组(数组每个元素都是指针) 四.二维数组指针(指向二维数组的指针) 五.指针数组和二维数组指 ...
最新文章
- 在IDE中刷LeetCode,编码调试一体化,刷题效率直线up!
- catia 创成钣金设计_弯曲的钣金设计技巧
- 三大组件与三大优势 SUSE发布CaaS平台为哪般?
- 【转】Alert Log Messages: Private Strand Flush Not Complete [ID 372557.1]
- python在当前目录创建txt文件-python根据txt文本批量创建文件夹
- 浅析ASP.NET的Page.IsPostBack 属性http://www.sina.com.cn 2008年05月06日 11:33 IT168.com
- 新版 C# 高效率编程指南
- C++学习之路 | PTA乙级—— 1036 跟奥巴马一起编程 (15 分)(精简)
- 收获,不止SQL优化——抓住SQL的本质--读过程
- linux之我常用的20条命令(之一)
- linux常见问题解决方法,Ubuntu 下2个常见问题解决方法
- Atitit 标签式tab 切换的实现 Softdev=declare+intercept 申明+解释 软件=代码+文档 软件=数据结构+算法 软件=程序+数据+文档 申明式 decla
- 增强旋转不变LBP算法及其在图像检索中的应用
- IDEA返回上一步和下一步快捷键无效:Ctrl+Alt+左箭头 Ctrl+Alt+右箭头
- 华为U5800刷机,Root权限
- mac无法安装dmg文件,报无可装载系统错误
- 计算机专业考研英语二国家线多少分,考研英语二国家线多少,2019年考研英语二国家线?...
- 世界的本质是什么---辩证的唯物论
- python表白代码照片墙-这个七夕节,用Python为女友绘制一张爱心照片墙吧!
- HTML 具体是用来做什么的?
热门文章
- 尚硅谷在线教育九:尚硅谷在线教育NUXT搭建前台环境以及相关页面的编写
- 论文阅读:2021.11.23~2021.12.1
- 武大计算机保研北大,17名北大毕业生保研到武大?网友说亏大了,其实这些学生赚大了!...
- matlab 实验四 数据处理与多项式计算
- 苹果手机来电归属地_手机号码归属地能否取消?工信部回复!
- 从包工头到程序猿(六)汶川地震
- 温湿度传感器的学习笔记
- 【笔试面试】HR面的面试技巧
- Yahoo Programming Contest 2019 D-Ears
- NANO开发套件SD卡烧录+opencv配置+tensorrt+cuda10.2