数组与指针

一、数组名作为函数参数

传递方式:地址调用——将实参数组首地址传给虚参

swap函数的正确形式

swap函数的几种错误形式

传值和传指


传值只改变形参的值,交换后变量值不能返回

void swap(int x,int y)

{

    int t;

    t=x;x=y;y=t;

}


传指改变实参,只改变指针指向,变换后的指针值也不能被返回

void swap(int *p1,int *p2)

{

    int *p;

    p=p1;p1=p2;p2=p;

}


p为野指针,没有赋初值,会出现段错误

 void swap(int *p1,int *p2)

{

    int *p;

    *p=*p1;*p1=*p2;*p2=*p;

}

输入a和b两个函数,按先小后大的顺序输出a和b

#include <stdio.h>

main()

{

        int *p1,*p2,*p,a,b;

}

二、字符指针——指向字符型数据的指针变量

作用——使用字符指针指向一个字符串

区别数组表示字符串字符指针表示字符串 

①定义不同

②初始换含义不同

char str[10 ]={"China"};                //可看为变量,返回值可修改

表示定义一个字符数组str,前5个元素分别赋初值为’C'、’h’、’i'、’ n'、’ a',后面的5个赋初值为’\0’,字符串”China”'在内存中存放的首地址就是数组的数组名str。

char*ptr="China ;                //常量,返回值不可修改

表示定义字符指针变量ptr,并在定义时用字符串"China"在内存中的首地址为指针变量ptr赋初值。
 

③赋值方法和含义不同

char *ptr,str[10];ptr=“China;

字符串的首地址赋给了ptr.

char *ptr,str[10];str="China" ;

数组名代表的是数组的首地起,是一常量,因此,不能用赋值方法。将字符串赋给字符数组必须使用函数strcpy。

④输入字符串时不同

char *ptr,str[10];scanf('" %s",str);
用字符指针输入字符串时,必须确保字符指针事先已指向了一个数组的首地址。

ptr=str;

⑤字符数组的数组名是一个地址常量,它的值 是不能改变的,而字符指针是一个变量,它的 值是可以改变的。

⑥字符数组可用于存放字符串,直接通过数组元素存取字符串属于直接寻址,字符指针则属于间接寻址。

字符指针作为函数参数

 mid(s,s1, m, n) ——截取函数

下列代码默认是s1后m位后默认有大于n个字符

char  *mid(char *s, char *s1, int m, int n)

{

        int  i;  

        for(i=m-1; i<m+n-1; i++)        

        *(s1+i-m+1)=*(s+i);          //s1-i-(m-1),s1下标从0开始,检查是否越界

        *(s1+n)='\0';                     //人为添加结束标志,否则不能称为字符串

         return(s1);

}

Left(s, s1,n) ——左截函数

char  *left(char *s, char *s1, int n)

{

        int i;  

        for(i=0; i<n; i++)        

        *(s1+i)=*(s+i);  

        *(s1+n)='\0';  

        return(s1);

}

Right(s, s1,n) ——右截函数

char *right(char *s, char *s1, int n)

{

        int i, m;  

        m=strlen(s);  

        for(i=0; i<n; i++)      

        *(s1+i)=*(s+m-n+i);  

        *(s1+n)='\0';  

        return(s1);

}

指针和数组间的联系

        一个变量有地址,数组中包含的若干元素也有地址,指针变量即可指向变量,当然也可指向数组元素和数组。

        指针的算术运算和关系运算常常是针对数组中的元素而言的。指向同—数组中不同元素的两个指针的关系运算是比较所指元素在数组中的前后位置关系。而指针的算术运算则是移动指针的指向,使其指向数组中的其它元素。
        在表达式中,数组名被自动转化为指向数组中第一个元素的常量指针。

数组的指针——数组的起始地址

元素的指针——数组元素的起始地址

 

 

 

 引用一个数组元素

下标法——a[i]形式

指针法——*(a+i)或*(p+i)

当有:int a[10],*p;
        p=&a9;p+t时,
        是合法的,系统是按*(a+10)处理,即先找出(a+10)的值(是一个地址)然后找出它所指向的单元的内容。

p++与*(p++)等价:先引用,后加1。
(p++)与*(++P)的作用不同。后者是先加1,后引用。
(*P)++表示将p指向的元素值加1。
 

虽然a和p都指向了数组的首地址,但数组名a是个她址常量,不能通过赋值操作改变它的值,指针变量p是个变量,可以通过赋值运算改变它的值,从而使p指向数组中的其它元素。
 

虽然p+1和p++都指向当前指针所指单元的下一个元素,

但p+1并不改变当前指针的指向,p仍然指向原来所指向的元素,p+1并非将指针变量p的值简单的加1个字节,事实上,它是加上1*sizeof(基类型),这里,基类型为int,因此,每执行一次p+1就相当p加上2个字节。

而p++相当于执行p=p+1,因此p++操作改变了指针p的指向,表示将指针变量p向下移动一个元素位置,即指向下一个元素。
 

数组元素的输入输出方法

  • 下标法引用数组元素

main()

{

        int a[10],i;  

        for(i=0;i<10;i++)      

        scanf(“%d”,&a[i]);  

        for(i=0;i<10;i++)      

        printf(“%d”,a[i]);

}

  • 数组名法引用数组元素

main()

{

        int a[10],i;    

        for(i=0;i<10;i++)          

        scanf(“%d”,a+i);    

        for(i=0;i<10;i++)          

        printf(“%d”,*(a+i));

}

  • 指针变量法引用数组元素

main()

{

        int a[10],*p,i;  

        p=a;  

        for(i=0;i<10;i++)      

        scanf(“%d”,p+i);  

        for(i=0;i<10;i++)      

        printf(“%d”,*(p+i));

}

  • 通过指针变量自增运算引用数组元素

main( )

{

        int a[10],*p;  

        for(p=a;p<a+10;p++)      

        scanf(“%d”,p);  

        for(p=a;p<a+10;p++)      

        printf(“%d”,*p);

}

自增运算执行效率高,利用自增运算代替了指针的算术操作,实现了指针的移动,其余算法效率相同.

  • 指针的下标表示法引用数组元素

main()

{

        int a[10],*p,i;  

        p=a;  

        for(i=0;i<10;i++)      

        scanf(“%d”,&p[i]);  

        for(i=0;i<10;i++)      

        printf(“%d”,p[i]);

}


%d 有符号10进制整数 
%i 有符号10进制整数 
%o 无符号8进制整数 
%u 无符号10进制整数 
%x 无符号的16进制数字,并以小写abcdef表示
%X 无符号的16进制数字,并以大写ABCDEF表示
%F/f 浮点数 
%E/e 用科学表示格式的浮点数 
%g 使用%f和%e表示中的总的位数表示最短的来表示浮点数 G 同g格式,但表示为指数 
%c 单个字符 
%s 字符串

认为是(*p++)这一部分运算完成,才再data1=(*p++);实际上是先赋值,后自加

二维数组

 通过列指针访问二维数组

 

        在调用数组的时候,*a和a[]的作用是一致的——都是传入数组a[]的第0个元素的地址,即首地址。
        如果需要获取数组中的第i个元素,我们也有两种方法:*(a+i)或a[i],且有*(a+i) == a[i]。
        那么,当我们在一个n行m列的二维数组中调用第i行的元素时,我们可以用a[i]来指代从a[i][0]一直到a[i][m]的所有元素的集合。

(*p)[m]指针用于二维数组

char ch[5][3] = {{'a','d','e'},{'w','p','u'},{'r','t','y'},{'1','4','6'},{'g','k','l'}};
void printArr(char (*p)[3],int n)    //用(*p)[3]表示数组的一行 
{
    int i;
    for(i = 0; i < 3; i++)
    {
        printf("%c\t",*(*(p+n)+i));    //用*(*(p+n)+i)可以输出第n行第i列的元素 
    }
}
 

请输入您想输出的元素的行(<3)数:2

r         t         y

二维数组元素a[i][j]的4种等价表示形式

1.a[i][j]

2.*(a[i]+j)

3.*(*(a+i)+j)

4.(*(a+i))[j]


行指针 (*p)[N],引用二维数组元素a[i][j]

1.p[i][j]

2.*(p[i]+j)

3.*(*(p+i)+j)

4.(*(p+i))[j]


行指针转换为列指针

示例1:用列指针输出二维数组。

#include <stdio.h>

void main()

{

   int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

   int *p= a[0];   // 列指针的定义法

   for(; p < a[0] + 12; p++)

   {

     printf("%d ",*p);

   }
 
    return;

}

示例2:用行指针输出整个二维数组。

#include <stdio.h>

void main()

{

   int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

   int (*p)[4]= &a[0]; // 行指针定义法或者int (*p)[4]= a;

   int i, j;

 

   for(i = 0; i < 3; i++)

     for(j = 0; j < 4; j++)

   {

     printf("%d ",*(*(p + i) + j));

   }

    return;

}

二维数组元素地址计算表

表示形式

含义

地址

a

二维数组名、数组首地址、0行首地址

2000

a[0], *(a+0), *a

0行第0列元素地址

2000

a+1, &a[1]

1行首地址

2008

a[1], *(a+1)

1行第0列元素地址

2008

a[1]+2,*(a+1)+2

&a[1][2]

1行第2列元素地址

2012

*(a[1]+2),a[1][2]

*(*(a+1)+2)

1行第2列元素的值

元素值为13

字符指针变量和字符数组

1.字符数组由若干个元素组成,每个元素存放一个字符,而指针变量中存放的是地址(字符串首地址),绝不是将字符串放到字符指针变量中。
⒉赋值方式:对字符数组只能对各个元素赋值,下列方法不正确。
        char str[14] ;
        stre=“I love China!";

    而对指针变量可采用下面方法赋值:
        char*a;
        a="I love China!";

3.对字符指针变量赋初值:

                char *a="I love China!".

等价于:    char *a;
                a="I love China!":

                char str[14]={"I love China!"};
不等价于: char str[14);
                str[]="I love China!";(写法也错误)

4.定义了一个字待数组,在编译时为他分配内存单元,有确切地址。而定义一个字符指针变量时,给指针变量分配内存单元(只能存放一个地址),没有实际的字符串存储单元。因而下面输入是很危险的。

                char *str;

                scanf("%s", a);     //野指针

应为:        char *a, str[10];

                a=str;

                scanf("%os", str);

5、指针变量的值是可以改变的

指针数组

它适用于用来指定若干个字符串,使字符串处理更加灵活

二级指针

 

*p指向地址,%s输出对应字符串

**p则是指针变量,需用%c输出,且只输出字符串第一个字符。 

动态存储

        动态数据结构—结点对于数据个数变化 较大时,存储空间得到100%的利用, 是由于在编译时,不分配结点的存储空 间,需要时,临时申请,系统再分配存储空间。

1.melloc

C语言提供了一个动态内存开辟的函数:
void malloc (size_t size);*
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
如果开辟成功,则返回一个指向开辟好空间的指针。
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

2.calloc

C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配。原型如下:
void* calloc (size_t num, size_t size);
函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

3.free

C语言提供了函数free用来做动态内存的释放和回收的,函数原型如下:
void free (void ptr);*
free函数用来释放动态开辟的内存。
如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。

4.realloc

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。 函数原型如下:
void realloc (void ptr, size_t size);**
ptr 是要调整的内存地址
size 调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。
realloc在调整内存空间的是存在两种情况:
        情况1:原有空间之后有足够大的空间
内存之后直接追加空间,原来空间的数据不发生变化。
        情况2:原有空间之后没有足够大的空间
扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。
上述的两种情况,realloc函数的使用就要注意一些。

最后都要用free函数释放内存

一维动态数组的实现

#include <stdio.h>
#include <stdlib.h>
main( )
{int  *p, n, i, sum=0;
  printf("Please  enter  array size:");
  scanf("%d", &n);
  p=(int *)calloc(n, sizeof(unsigned int));//申请
  printf("Please  enter  the  score.");
  for(i=0; i<n; i++)
     {scanf(“%d”, p+i);//使用申请的内存
       sum+=*(p+i);}
  printf("sum=%d, aver=%f\n", (float)sum/n);
  free(p);//使用完毕后释放内存
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值