打印数组元素值的方式:(一维数组)
arr[i]
*(arr+i)
*(arr++) //error
i[arr]
*(p+i)
*(p++)
p[i]
***1,指针和二维数组:***
总结:对于int arr[2][3]的数组来说,arr[0][0]的类型是int ,arr[0]的类型是int *(因为arr[0] == &arr[0][0])
又因为arr == &arr[0] ,为什么arr不是int **?
(1)因为arr+1移动了12个字节(一维数组的的大小),如果是int **,应该加一移动4个字节,明显不符合。
(2)arr[0]是一维数组的数组名,能够代表整个数组,如果将数组名取址赋值个一个指针变量,相当于该指针指向了整个数组,而不是首元素。
因此:对于arr来说,arr的类型是一个指向一维数组的指针,即数组指针
2,数组指针:指向一维数组的指针。
本质:指针
格式:
存储类型 数据类型 (指针变量名) [元素个数];
注意:[]的优先级比要高,所以变量名会首先和[]结合表示的是数组名,而不是指针变量名。
所以需要提高*的优先级,故加()。
分析
存储类型:该数组指针自身的存储位置
数据类型: 所指向一维数组的元素类型
该指针所指向的类型:数据类型 [元素个数]
该指针自己的类型:数据类型 ( * ) [元素个数]
int arr[5];
//定义一个数组指针指向该一维数组
int (*p)[5] = &arr;
指针的本质:
用来操作一片连续的空间才有意义。
int arr[3][4];
//定义一个数组指针
int (*p)[4] = &arr[0];
int (*p)[4] = arr;
3,指针数组:数组元素类型为指针类型
本质:数组
格式:
存储类型 数组类型 * 数组名[元素个数]
int a,c,b;
定义一个指针数组用来存储三个变量的地址
int * p[3] = {&a,&b,&c};
访问:
int i;
for(i=0;i<3;i++)
{
printf("%d",*p[i]);
printf("%d",*(*(p+i)));
}
定义一个指针数组,用来存储二维数组中的每一个小一维?
int arr[3][4];
int *p[3] = {NULL};
for(i=0;i<3;i++)
{
p[i] = arr[i];
}
*(p[i] + j)
((p+i)+j)
char str[100] = {“wangjia”};//在栈区开辟了100个字节的空间,用来完全存储"wangjia"每一个字符
str[0] = ‘j’;//OK
char *str = “wangjia”; //在栈区开辟了4个字节的空间,只能存储&‘w’
注意:此时通过p去操作还是操作的是原空间
*str = ‘k’; //error
char *pstr[5] = {“wangjia”,“haha”,“xixi”,“gaga”,“hehe”};
4,const修饰的指针:
const :被const修饰的变量表示只读
int a = 90;
conat int a = 89;
总结:
(1)对于const来说,修饰完之后的变量的存储位置不会发生改变(依赖于之前的存储位置),只不过被常量化了
(2)const 没有修饰谁,谁就可以更改,const修饰谁,谁就不能被更改。
分为两类:
(1)指向常量的指针:
int a;
int *p = &a:
int const p = &a;
const int p = &a;//代表p不能被更改但是p的指向以及通过a去修改a的值都是可行的
(2)指针常量:
int * const p = &a; //代表指针的指向不能被更改,但是可以通过给p 以及给a去赋值引起a值的改变
(3)双重修饰:const int * const p = &a;//代表*p和p的指向均不可发生改变。
int const * const p = &a;
1,拆分一个带有空格的字符串,将拆分之后的字符串保存在字符指针数组中
eg:
char str[100] = {“hello world wangjia”};
升级版:char str[00] = {" wang jia jia hh"};
#include <stdio.h>
#define N 100
int main(int argc, const char *argv[])
{
//定义一个字符串
char str[N] = {'\0'};
//定义一个指针指向该数组的首元素
char *p = str;
printf("请输入一个需要分割的字符串:\n");
gets(p);
//定义一个字符指针数组用来存储分割之后的字符串的地址
char *pStr[10] = {NULL};
int count = 0;
//遍历p所指向的数组
while(*p)
{
//判断该位是否为空格
while(' ' == *p)
{
p++;
}
//将该位保存再指针数组的第一个元素中
if('\0' != *p)
{
pStr[count++] = p;
}
else
{
break;
}
p++;
//判断该位不是空格,如果不是,则往后移动
while(' ' != *p)
{
p++;
}
//当遇到第一个空格时,将空格用'\0'代替
*p = '\0';
p++;
}
printf("拆分之后的字符串为以下:\n");
int j;
for(j=0;j<count;j++)
{
puts(pStr[j]);
}
return 0;
}
你需要《C程序设计语言》。数组名和数组指针是不一样的。当编译器看到int arr[3][3]; 时,会给拨9个int类型大小的内存空间,而arr这个数组名则是这段内存开头处的地址。这是一个特殊的常量,不占内存空间,在编译时就知道。在代码中可以表示这个数组,也可以表示这个数组开头处的地址。编译器在看到arr[1]时,会给你改成*(arr + 1) 。然后编译器先看到arr + 1,它认为arr能与整数相加减,所以是一个地址型常量,然后算出arr + 1的值,常量加常量还是常量,这是一个典型的常量表达式,结果还是在编译时就知道。然后编译器看到了*,然后就认为你要取这个常量地址所指向的内存区域的值,然后程序正常进行。编译器又看到了&arr。这时,由于arr的值并没有内存空间,所以编译器认为你这里的arr是表示数组。所以就取到了这个数组的地址。然后程序继续运行,编译器看到了&(arr + 1); 由于优先级,它先处理arr + 1,编译器认为arr能与整数相加减,所以代表指针常量。然后计算arr + 1得到一个常量结果,然后编译器看到了&,然后就报错了,因为就像&1一样,编译器不知道你取一个常量的地址算几个意思