admin 管理员组

文章数量: 887021


2024年1月28日发(作者:y2系列电机线圈数据表)

C语言程序设计 指针C语言学习

重点:

1、C语言中指针的概念

2、指针变量的相关操作

3、指针与数组的关系

4、内存空间的动态分配

第1节 C语言中指针

一、指针与指针变量

一台计算机的内存单元非常多,为了相互区分,就给它们采取编号的方法,按十进来说,从0开始编号,即0,1,2„„,这种对每个内存单元的唯一的编号叫做内存单元的地址。计算机对内存的访问一般采取“按地址访问”的方式。

变量(指前面所讲的普通变量)的实质对应的是内存单元,对变量的操作实质是对相应内存单元中所存放的数据的操作:给变量赋一个值,实质是将一个值存入与此变量对应的内存单元;读取一个变量的值,实质是从对应的内存单元中取出存放的数据。

有时,我们要用到内存单元的地址,这种情况下,可利用C语言中的“指针”数据类型来实现。

指针就是变量的地址,实质是内存单元的地址。

可以用变量来存放指针,称为指针变量,但跟普通变量不同的是,普通变量存放数据,指针变量存放的是变量的地址,即内存单元的地址。

1、指针变量的定义

数据类型符 *变量名;

如:

int *a,*b;

float *fp;

2、指针变量的赋值

1)初始化赋值

数据类型 *指针名=初始地址值;

例:

int x=20;//定义了一个普通的整型变量

int *p=&x; //定义了一个指向整型变量的指针变量,并让p指向变量x所对应的内存单元,即p中存入x所对应的内存单元的地址。如下图:

例:

int i;

int *p = &i;

int *q = p;

2)赋值语句赋值

int a;

int *p;

p = &a;

3、与指针相关的运算符

&:取地址运算符,获得变量的地址

*:访问指针所指变量内容的运算符

上例中,要获得内存单元10000中的内容有两种办法:

①直接访问:按变量名来存取变量值。上例中可通过x来实现;

②间接访问:通过存放变量地址的指针变量去访问。上例中可通过*p访问。

注意:p代表地址而*p代表内容。

例:

输入两个数,并使其从大到小顺序输出,用指针实现。

#include

void main( )

{

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

printf("n请输入两个整数:");

scanf ("%d%d",&a,&b);

p1=&a;

p2=&b;

if(*p1<*p2)

{

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

}

printf("a=%d,b=%dn",a,b);

printf("max=%d,min=%dn",*p1,*p2);

}

说明:

1、指针变量必须先定义,后赋值,最后才能使用!没有赋值的指针变量是没有任何意义的,也绝对是不允许使用的。如下例:

#include "stdio.h"

void main( )

{

int *p1,*p2;

printf("n请输入两个整数:");

scanf ("%d%d",p1,p2);

printf("max=%d,min=%dn",*p1,*p2);

}

例中的指针变量p1和p2没有赋值,使用时就会出错。

2、指针变量只能指向定义时所规定类型的变量。如果给指针赋值时,=号右边的指针类型与左边的指针类型不同,则需要进行类型强制转换。

例:

int a;

int *pi;

char *pc;

pi=&a;//pi指向a

pc=(char*)pi;//pc也指向了a,即pi和pc的值都是a的地址

3、普通变量随着类型的不同,在内存中所分配的内存单元可能也会发生变化。指针变量也是变量,在内存中也要占用一定的内存单元,但所有类型的指针变量都占用同样大小的内存单元,其具体大小取决于所使用的编译环境,如在VC6.0下为4个字节,在TC2.0下为2个字节。

二、指针和地址运算

1、指针变量的加、减运算

指针可以参与加、减运算,但其加、减的含义不同于一般数值的加减运算。如下例:

#include "stdio.h"

void main()

{

int *pi;

char *pc;

pi=(int *)1000;

printf("npi=%d",pi);

pc=(char *)1000;

printf("npc=%d",pc);

pi++;//pi的值将是1004 (假设int型占4B)

printf("npi=%d",pi);

pi-=2;//pi的值将是996

printf("npi=%d",pi);

pc++;//pc的值将是1001

printf("npc=%d",pc);

pc-=2;//pc的值将是999

printf("npc=%d",pc);

}

如果指针p是这样定义的:

ptype *p;

并且p当前的值是ADDR,那么:

p±n 的值=ADDR±n*sizeof(ptype)

即指针加上或减去一个整数相当于将指针以定义时所用的数据类型占用内存的字节数为单位向后或向前移动n个单位。

两个指针相加没有任何意义,但两个指针相减则有一定的意义,可表示两指针之间所相差的内存单元数或元素的个数,在后面的学习中就会体会到。

2、指针变量的关系运算

若p1和p2指向同一类型的变量,则

p1

p1>p2 表示p1所指的单元在p2之后

p1==p2 表示p1与p2指向共同的单元

若p1与p2指向的是同一数组中的元素(变量),则上述比较有意义,否则比较没有实际意义

第2节 指针与数组的关系

一、数组的指针与指向数组的指针变量

1、数组的指针:其实就是数组在内存中的起始地址。而数组在内存中的起始地址就是数组变量名,也就是数组第一个元素(下标为0)在内存中的地址。如下图:

p + 1指向数组的下一个元素,而不是简单地使指针变量p的值+1。其实际变化为p+1*size(size为一个元素占用的字节数)。

2、指向数组的指针变量:如果将数组的起始地址赋给某个指针变量,那么该指针变量就是指向数组的指针变量。如上图:

下面是对数组元素赋值的几种方法,它们从功能上是等价的:

方法一:

char str[10];

int k;

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

str[k]='A'+k; //也可写成*(str+k)='A'+k方法二:

char str[10],*p;

int k;

p=str;

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

p[k]='A'+k; //也可写成*(p+k)='A'+k

方法三:

char str[10],*p;

int k;

p=str;

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

*p++='A'+k; //相当于 *p='A'+k; p++;

注意:数组名是地址常量,切不可对其赋值,也不可做++或--运算。例如:int a[10];如果在程序中出现a++或a--则是错误的。

下面一个例子用来说明数组元素的各种不同引用方法:

#include

void main( )

{ int a[2],*pa,i;

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

a[i]=i+1;

pa=a;

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

printf("*(pa+%d):%dn",i,*(pa+i));

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

printf("*(a+%d):%dn",i,*(a+i));

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

printf("pa[%d]:%dn",i,pa[i]);

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

printf("a[%d]:%dn",i,a[i]);

}

例:设有如下定义:int a[]={1,2,3,4,5,6,7,8,9,10},*p=a,i;

下列对数组元素地址的正确表示是:

(A)&(a+1) (B)a++ (C)&p (D)&p[i]

二、二维数组与指针的关系

二维数组可看作是特殊的一维数组:其每个元素本身就是一个一维数组。C语言中的二维数组在内存中是按“行序优先”的方式排列。

看下例:

#include

#include

void main()

{

int a[2][3]={{1,2,3},{4,5,6}};

int i,j,*p;

p=&a[0][0];

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

{

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

printf("%8d%8d",p,*p++);

printf("n");

}

system("pause");

}

运行结果如下:

第3节 指针与字符串

用C语言表示字符串时有如下两种形式:

一、用字符数组实现

例:

#include

void main ( )

{ char string[] = "I love China!";

printf ("%sn", string);

printf ("%sn", string + 7);

}

二、用字符指针实现

例:

#include

void main ( )

{

char *string = "I love China!";

printf("%sn", string);

string+=7;

puts(string);

}

#include

void main ( )

{

char *string = "I love China!";

printf("%sn", string);

string+=7;

while(*string)

{

putchar(string[0]);//也可以写成putchar(*string);

string++;

}

}

三、字符指针变量与字符数组

char *cp; 与 char str[20];

1、str由若干元素组成,每个元素放一个字符;而cp中只存放字符串首地址。

char str[20]; str=“I love China!”; (′)

char *cp; cp=“I love China!”; (?)

2、str是地址常量;cp是地址变量

cp接受键入字符串时,必须先开辟存储空间

例 char str[10];

scanf(“%s”,str); (?)

而 char *cp;

scanf(“%s”,cp); (′)

改为:char *cp,str[10];

cp=str;

scanf(“%s”,cp); (?)

3、当字符指针指向字符串时,除了可以被赋值之外,与包含字符串的字符数组没有什么区别。

char str[10], *pstr;

pstr="12345"; //pstr指向"12345"

strcpy(str,pstr); //将pstr所指向的字符串复制到数组str中

pstr=str;

printf("The Length of str is: %dn", strlen(pstr)); //输出字符串的长度5

四、字符串与数组关系

字符串用一维字符数组存放

字符数组具有一维数组的所有特点

数组名是指向数组首地址的地址常量

数组元素的引用方法可用指针法和下标法

数组名作函数参数是地址传递

区别

存储格式:字符串结束标志

赋值方式与初始化

输入输出方式:%s %c

char str[]={“Hello!”}; (?)

char str[]=“Hello!”; (?)

char str[]={„H‟,„e‟,„l‟,„l‟,„o‟,„!‟}; (?)

char *cp=“Hello”; (?)

int a[]={1,2,3,4,5}; (?)

int *p={1,2,3,4,5}; (′)

char str[10],*cp;

int a[10], *p;

str=“Hello”; (′)

cp=“Hello!”; (?)

a={1,2,3,4,5}; (′)

p={1,2,3,4,5}; (′)

例:输入一组人员姓名,先按原序输出,再排好序后输出。

#include "stdio.h"

#include "stdlib.h"

#include "string.h"

#define RENSHU 50

#define N 10

void main()

{

char name[RENSHU+1][N];

int i,j,renshu;

printf("n请输入人数(1-%d):",RENSHU);

scanf("%d",&renshu);

if((renshu<1)||(renshu>RENSHU))

printf("n输入的人数超出范围!");

else

{

printf("n请输入%d个人的姓名,姓名最长五个汉字:n",renshu);

for(i=1;i<=renshu;i++)

scanf("%s",&name[i]);

printf("n排序前:n");

for(i=1;i<=renshu;i++)

printf("%8s",name[i]);

for(i=1;i

for(j=renshu;j>=i+1;j--)

if(strcmp(name[j],name[j-1])<0)

{

strcpy(name[0],name[j]);

strcpy(name[j],name[j-1]);

strcpy(name[j-1],name[0]);

}

printf("n排序后:n");

for(i=1;i<=renshu;i++)

printf("%8s",name[i]);

printf("n");

}

system("pause");

}

第3节 指针与动态内存分配

一、静态内存分配

当程序中定义变量或数组以后,系统就会给变量或数组按照其数据类型及大小来分配相应的内存单元,在程序运行过程中分配给它们的内存空间大小是不固定不变的,这种内存分配方式称为静态内存分配。

二、动态内存分配

动态内存分配是指在程序运行过程中,根据程序的实际需要来分配一块大小合适的连续的内存单元,即“按需分配”。

动态分配的内存大小可以由用户自行按需要确定。

例:编写程序利用C语言的随机函数rand产生一组(最多10000个)小于1000的随机数,先按产生的原顺序输出,再降序排序后并输出,要求在程序运行时先确定要产生的数字的个数,然后按要求根本内存空间。

此例中要产生数值的个数不定,可以由用户在程序运行时从键盘输入,然后将产生的数值放入一个数组即可。

为了建立跟要求的空间大小相符的数组,可以用空间的动态分配解决此问题。

动态分配的实现:

1、内存空间的分配:

C语言中动态内存分配其实就是使用一个标准的库函数malloc,格式如下:

void *malloc(unsigned int size );

说明:

1)size这个参数的含义是分配的内存的大小(以字节为单位)。

2)返回值:失败,则返回值是NULL(空指针);成功,则返回值是一个指向空类型(void)的指针(即所分配内存块的首地址)。

3)malloc前面必须要加上一个指针类型转换符,如前面的(int *)。因为malloc的返回值是空类型的指针,一般应与右边的指针变量类型一致。

malloc所带的一个参数是指需分配的内存单元字节数,尽管可以直接用数字来表示,但一般写成如下形式:

分配数量*sizeof(内存单元类型符)

sizeof()是系统的一个标准函数,用于返回所指定的数据类型所占用的内存字节数。

malloc可能返回NULL,表示分配内存失败,因此一定要检查分配的内存指针是否为空,如果是空指针,则不能引用这个指针,否则会造成系统崩溃。所以在动态内存分配的语句的后面一般紧跟一条if语句以判断分配是否成功。

4)动态分配的内存需要有一个指针变量记录所分配内存的起始地址。

2、释放动态内存:

用free函数实现,格式如下

void free (void *block);

调用malloc和free函数的源程序中要包含stdlib.h或malloc.h。malloc和free一般成对出现!

实现上例的程序如下:

#include

#include

#include

#define N 10000

void main()

{

int i,j,n,*p;

printf("n请输入要产生的数据的个数(1--%d):",N);

scanf("%d",&n);

if((n<1)||(n>N))

printf("n输入的数值个数超出了要求的范围!n");

else

{

p=(int *)malloc((n+1)*sizeof(int));

if(p==NULL)

printf("n内存空间的分配不成功!n");

else

{

srand((unsigned)time(NULL));

//time返回从1970年 1月1日零时开始的秒数,srand用于初始化随机函数

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

p[i]=rand()%1000;

printf("n按原序输出:n");

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

printf("%8d",p[i]);

printf("n");

}

for(j=1;j

for(i=n;i>=2;i--)

if(p[i]>p[i-1])

{

p[0]=p[i];

p[i]=p[i-1];

p[i-1]=p[0];

}

printf("n按降序输出:n");

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

printf("%8d",p[i]);

printf("n");

}

system("pause");

}


本文标签: 指针 变量 内存 数组 地址