C语言12 指针基本操作2+指针与数组

===================数组和指针的基本关系: 数组大小和起始地址指针

1、C语言只有一维数组,而且其大小必须在编译期间确定下来。 但是其组元素可以是任何类型,如另外的数组。因此可以构建多维数组。

2、对一个数组,只可确定其大小,以及获得指向组下标为0的元素的指针。

    其他的关于数组的操作,如组下标等,也是经由指针进行的,二者是等价的。

3、int calender[12][31];

     sizeof(calender) = 12*31*4;  

   除了sizeof以外,其他的操作总被转换成为calender数组的起始元素的指针。

===================指针的基本操作

4、通过指针改变变量的值:

任何指针都是指向某类型的变量,可以给其赋变量地址,并经由指针改变变量的值。

int  *p; 
int  i;
p = &i;  
*p = 12;    

5、指针的偏移:

p+1; p++; ++p;

p-1;  p--;      --p;

表示 指向p指向的组元素的前后元素。

在内存中的地址偏移是 : (p的指向类型)*1

6、指针的加减

如果两个指针指向同一个组元素,则可以把两个指针相加减。   int p = q + i;

=============数组和指针

7、数组首地址和指针类型

int a[3], *p;

p = a; 是把数组a中下标为0的元素的地址赋给 p。即p = &a[0]...

区别 p = &a;    &a是一个指向数组的指针,而p是指向整型变量的指针,二者类型不匹配。

8、数组元素和指针

*a = a[0];   *a 是 a[0]的引用,属同一个元素。

    *(a+1) = a[1]; 

    *(a+i) = a[ i ];

9、二维数组的指针和行地址

int  a[12][31];  

    int *p;

    p = a[4]; //第五行首地址; 不是 p=&a[4]; a[4]是 int (*)[31]类型,& 则是变成int(*)类型。

p指向a[4]中下标为0的元素的地址: &a[4][0]... a[4]为a 第五个元素。

a[4]是a的第五个元素,是12个有31个整数元素的数组之一。 a[4]也表现为一个有31个整型元素的组行为。

    a[4][7] = *( a[4] + 7) = *( *(a + 4) + 7);

-------------

& 是取地址运算符。而* 是指针运算符或叫间接访问运算符。

(1)a[0]+1=&a[0][1]=*(a+0)+1;

同理:a[0][1]=*(a[0]+1)=*(*(a+0)+1)=*(a+1);

(2)a[i]的性质:a如果是一维数组名,这a[i]为组元素有物理内存。如果a是二维数组,则a[i]代表一维数组名,只是一个地址并不占有内存单元。

(3)二维数组名是指向行的,如a+1;1表示一行中全部元素所占字节数。而a[0]=*a是指向列的,如a[0]+1。

@ 行指针前加上*,就转换成了列指针。而列指针前加上了&,就转换成了行指针了。

@ 同样&a[i]在这里并不是a[i]的物理地址,没有a[i]这个变量,这只是一种地址的计算方法。

@ a+i和&a[i]是指向行的,而a[i]和*a,*(a+i)是指向列的。

----------------------

10、指向数组的指针

声明指向数组的指针:  参考函数的指针 int (*p)();

    int (*p) [31];     

int a[12][31]; 

p = a; 

则 *p是一个有31个整型元素的数组。 p指向数组的第一个元素 a[0]。 

	char arrayT[2][5]={0};
	char *s[3] = {"aaaaa", "bbb", "ccccc"};
	char (*p)[5] = &arrayT[0];
	p = arrayT+1;
	char arrayB[] = "bbbc";
	p = &arrayB;

11、数组行指针和列指针的转换:

数组行指针 加上* 成为列指针; 数组列指针加上 &成为行指针。

12、含多个指针的数组:

char *argv[ ]表示指针数组;区别char (* argv)[ ]数组指针。

@清空 一整年的日历:

int  calender[12][31];  
int  month;
for( month=0; month<12; month++)
{
    int day;
    for(day = 0; day<31; day++)
    {
        calender[month][day] = 0;
    }
}
int (*monthp)[12];
for(monthp = calender;  monthp<&calender[12]   monthp++)
{
    int *dayp;         //每个月的操作
    for(dayp= *monthp;  dayp<&(* monthp)[31];  dayp++ )
    {
        *dayp = 0;
    }
}

///

1、如何在C中为一个数组分配空间。

如果是栈的形式,Type s[N]定义后系统自动分配空间,分配的空间大小受操作系统限制;

若是堆的形式,Type *s; s = (Type *)malloc(sizeof(Type) * N);分配的空间大小不受操作系统限制。

///例题分析

1、数组名作为首地址

指出下面代码的输出,并解释为什么。

main()
{
	int a[5]={1,2,3,4,5};
	int *ptr=(int *)(&a+1);//指针是数组类型,+1相当于加20.如果是(a+1)是+4
	printf("%d  %d\n", a, ptr); 
	printf("%d, %d", *(a+1),*(ptr-1));
}

输出:1245036 1245056 2,5

*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5

&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int).

int *ptr=(int *)(&a+1);

则ptr实际是&(a[5]),也就是a+5

原因如下:

&a是数组指针,其类型为 int (*)[5];

而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同

a是长度为5的int数组指针,所以要加 5*sizeof(int),所以ptr实际是a[5].

但是prt与(&a+1)类型是不一样的(这点很重要),所以prt-1只会减去sizeof(int*).

a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].

2、数组名作为首地址

   题目如下,找出其中的不妥之处。

{
    char *p1, *p2;
    char ch[12];
    char **pp;
    p1 = ch;  //指向数组首地址 &ch[0]
    pp = &ch; //错误用法

    p2 = *pp;
}

问p1和p2是否相同

    首先,数组ch是没有初始化的。其次,一个比较隐含的地方是,数组名可以代表数组第一个元素的首地址,这个没有问题,但是,数组名并非一个变量,数组分配完成后,数组名就是固定的,地址也是固定的。这样导致的结果就是绝对不能把数组名当作变量来进行处理。上述题目中,pp=&ch,显然是把数组名当作指针变量来使用了,这样肯定出问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值