随笔 - 56, 文章 - 0, 评论 - 0, 引用 - 0
数据加载中……

函数、数组和指针

1、#define EOF (-1)
为什么-1?一般情况下,getchar()返回一个范围在0到127之间的值,因为这些值是与标准字符集相对应的值。但如果系统识别一
个扩展的字符集,则可能返回从0到255的值。在每种情况下,值-1都不对应任何字符,所以可以用它来表示文件结尾。

2、代码:

 1#include<stdio.h>
 2void display(char,int,int);
 3int main()
 4{
 5    int cols,width;
 6    char ch;
 7
 8    printf("Enter a character and two integers:\n");
 9    while((ch=getchar())!='\n')
10    {
11        scanf("%d %d",&cols,&width);
12        display(ch,cols,width);
13        printf("Enter another character and two integers;\n");
14        printf("Enter a newline to quit.\n");
15    }

16
17    return 0;
18}

19
20void display(char ch,int cols,int width)
21{
22    int i;
23    int j;
24
25    for(i=0;i<cols;i++)
26    {
27        for(j=0;j<width;j++)
28            putchar(ch);
29
30        printf("\n");
31    }

32}
显示结果为:
1Enter a character and two integers:
22 3
3ccc
4ccc
5Enter another character and two integers;
6Enter a newline to quit.
解释:
本来是一个循环体,但是执行一次后就结束了,错在哪里呢?换行符,输入的为“c 2 3\n",3后面是一个回车即换行符,scanf()
函数将该换行符留在了输入队列中。与scanf()不同,getchar()并没有跳过换行符。所以在循环的下一个周期,在您有机会输入
任何其他内容之前,这一换行符由getchar()读出,然后将其赋值给ch,而ch为换行符正式终止循环的条件。修改为:
 1#include<stdio.h>
 2void display(char,int,int);
 3int main()
 4{
 5    int cols,width;
 6    char ch;
 7
 8    printf("Enter a character and two integers:\n");
 9    while((ch=getchar())!='\n')
10    {
11        scanf("%d %d",&cols,&width);
12        display(ch,cols,width);
13        while(getchar()!='\n')
14            continue;
15        printf("Enter another character and two integers;\n");
16        printf("Enter a newline to quit.\n");
17    }

18
19    return 0;
20}

21
22void display(char ch,int cols,int width)
23{
24    int i;
25    int j;
26
27    for(i=0;i<cols;i++)
28    {
29        for(j=0;j<width;j++)
30            putchar(ch);
31
32        printf("\n");
33    }

34}

3、定义带有参数的函数:形式参量
可以使用ANSI之前的形式:
 1#include<stdio.h>
 2void show_n_char(char,int);
 3
 4int main()
 5{
 6    show_n_char('c',2);
 7
 8    return 0;
 9}

10
11void show_n_char(ch,num)
12    char ch;
13    int num;
14{
15    int i=0;
16    for(;i<num;i++)
17        putchar(ch);
18
19    putchar('\n');
20}

21

4、代码:
 1#include<stdio.h>
 2int show();
 3
 4int main()
 5{
 6    show();
 7
 8    return 0;
 9}

10
11int show()
12{
13    int i=0;
14    if(i==0)
15        return 1;
16    else
17        return -1;
18
19    printf("This line would not display.\n");
20}

return语句使printf()语句永远不会执行。

5、指针简介

1int *ptr;
2int pooh;
3ptr=&pooh;
ptr和&pooh的区别在于前者为一变量,而后者是一个常量。
1int x;
2int temp;
3int *u;
4u=&x;
把x的值存在temp中,需要使用一下语句:
temp=*u;
因为u的值是&x,所以u指向x的地址,意味着*u代表x的值。不要写成这样:
temp=u;
上面的语句中,赋给temp的只是x的地址而不是x的值,所以不能实现数值的交换。

1、代码1
 1#include<stdio.h>
 2#define SIZE 4
 3int main()
 4{
 5    int some_data[SIZE]={1,2};
 6    int i;
 7    printf("%2s%14s\n","i","some_data[i]");
 8    for(i=0;i<SIZE;i++)
 9        printf("%2d%14d\n",i,some_data[i]);
10
11    return 0;
12}
显示结果为:
1 i  some_data[i]
2 0             1
3 1             2
4 2             0
5 3             0
当数值数目少于数组元素数目时,多余的数组元素被初始化为0.如果不初始化数组,数组元素和未初始化的普通变量一样,
 其中存储的无用的数值;但是如果不分初始化数组,未初始化的元素则被设置为0.
 
 2、在C99规定,在初始化列表中使用带有方括号的元素下表可以指定某个特定的元素:
 int arr[6]={[5]=212};
 1#include<stdio.h>
 2int main()
 3{
 4    int days[12]={31,28,[4]=31,30,31,[1]=29};
 5    int i;
 6
 7    for(i=0;i<12;i++)
 8        printf("%2d %d\n",i+1,days[i]);
 9
10    return 0;
11}
显示结果为:
 1 1 31
 2 2 29
 3 3 0
 4 4 0
 5 5 31
 6 6 30
 7 7 31
 8 8 0
 9 9 0
1010 0
1111 0
1212 0

3、
float ran[5][12];
理解这个声明的方法是首先看rain[5],说明rain是一个包含5个元素的数组。至于每个元素的情况,需要看声明的其余部分
float [12],说明每个元素的类型是float[12];也就是说rain有5个元素,并且每个元素都是包含12个float数值的数组。

4、

1int flizy[5];
2flizy==&flizy[0];
3flizy和&flizy[0]都代表首元素的内存地址,两者都是常量,因为在程序的运行过程中它们保持不变。

5、
1int dates[5];
2dates+2==&date[2]  //相同的地址
3*(dates+2)==dates[2//相同的值

dates[2],意思为*(dates+2),即“寻址到内存中的dates,然后移动2*sizeof(int)个字符地址,再取出数值”。
注意区分*(dates+2)和*dates+2。间接运算符(*)的优先级高于+,因此后者等价于:(*dates)+2。

6、
无论在任何情况下,形式int *ar都表示ar是指向int的指针。形式int ar[]也可以表示ar是指向int的指针,但只是在声明形式
参量的时候才可以这样使用。如:

1int sum(int *ar,int n)
2{
3//代码
4}

5
6int sum(int ar[],int n);
7{
8//代码
9}

是等价的。

7、代码分析:

 1#include<stdio.h>
 2#define SIZE 10
 3int sum(int ar[],int n);
 4int main()
 5{
 6    int marbles[SIZE]={20,10,5,39,4,16,19,26,31,20};
 7    long answer;
 8    answer=sum(marbles,SIZE);
 9    printf("The total number of marbles is %ld.\n",answer);
10    printf("The sizeof of marbles is %d bytes.\n",sizeof marbles);
11
12    return 0;
13}

14
15int sum(int ar[],int n)
16{
17    int i;
18    int total=0;
19
20    for(i=0;i<n;i++)
21        total+=ar[i];
22    printf("The size of ar is %d bytes.\n",sizeof(ar));
23
24    return total;
25}
显示结果为:
1The size of ar is 4 bytes.
2The total number of marbles is 190.
3The sizeof of marbles is 40 bytes.

解释:
marbles的大小为40个字节,因为marbles包含10个int类型的数,每个数占4个字节,所以40个字节。但是ar只占4个字节,因为
ar本身并不是一个数组,只是一个指向marbles的首元素的指针。对于采用4字节地址的计算机系统,指针的大小为4个字节。

8、
*start++;
一元运算符*和++具有相等的优先级,但它在结合时是从右向左进行的。意味着++应用于start,而不是应用于*start。也就是
说,是指针自增1,而不是指针所指向的数据自增1。如果程序使用(*start)++,那么会十一偶那个start所指向的数据,然后
再使该数据自增1,而不是使指针自增1.这样指针所指向的地址不变,但其中的元素却变成了一个新数据。例如:

 1#include<stdio.h>
 2int data[2]={100,200};
 3int moredata[2]={300,400};
 4
 5int main()
 6{
 7    int *p1,*p2,*p3;
 8
 9    p1=p2=data;
10    p3=moredata;
11
12    printf("*p1=%d *p2=%d *p3=%d\n",*p1,*p2,*p3);
13    printf("*p1++=%d *++p2=%d (*p3)++=%d\n",*p1++,*++p2,(*p3)++);
14    printf("*p1=%d *p2=%d *p3=%d\n",*p1,*p2,*p3);
15
16    return 0;
17}
显示结果为:
1*p1=100 *p2=100 *p3=300
2*p1++=100 *++p2=200 (*p3)++=300
3*p1=200 *p2=200 *p3=301

9、代码:
 1#include<stdio.h>
 2int main()
 3{
 4    int urn[5]={100,200,300,400};
 5    int *ptr1,*ptr2,*ptr3;
 6
 7    ptr1=urn;
 8    ptr2=&urn[2];
 9
10    printf("pointer value,dereferenced pointer,pointer address:\n");
11    printf("ptr1=%p,*ptr1=%d,&ptr1=%p\n",ptr1,*ptr1,&ptr1);
12
13    ptr3=ptr1+4;
14    printf("\nadding an int to a pointer:\n");
15    printf("ptr1+4=%p,*(ptr1+3)=%d\n",ptr1+4,*(ptr1+3));
16
17    ptr1++;
18    printf("\nvalues after ptr1++\n");
19    printf("ptr1=%p,*ptr1=%d,&ptr1=%p\n",ptr1,*ptr1,&ptr1);
20
21    ptr2--;
22    printf("\nvalues after --ptr2\n");
23    printf("ptr2=%p,*ptr2=%d,&ptr2=%p\n",ptr2,*ptr2,&ptr2);
24    --ptr1;
25    ++ptr2;
26
27    printf("\npointers reset to original values:\n");
28    printf("ptr1=%p,ptr2=%p\n",ptr1,ptr2);
29
30    printf("\nsubtracting one pointer from another:\n");
31    printf("ptr2=%p,ptr1=%p,ptr2-ptr1=%d\n",ptr2,ptr1,ptr2-ptr1);
32
33    printf("\nsubtracting an int from a pointer:\n");
34    printf("ptr3=%p,ptr3-2=%p\n",ptr3,ptr3-2);
35
36    return 0;
37}
显示结果为:
 1pointer value,dereferenced pointer,pointer address:--------------1
 2ptr1=0022FF50,*ptr1=100,&ptr1=0022FF4C
 3
 4adding an int to a pointer:--------------------------------------2
 5ptr1+4=0022FF60,*(ptr1+3)=400
 6
 7values after ptr1++----------------------------------------------3
 8ptr1=0022FF54,*ptr1=200,&ptr1=0022FF4C
 9
10values after --ptr2----------------------------------------------4
11ptr2=0022FF54,*ptr2=200,&ptr2=0022FF48
12
13pointers reset to original values:-------------------------------5
14ptr1=0022FF50,ptr2=0022FF58
15
16subtracting one pointer from another:----------------------------6
17ptr2=0022FF58,ptr1=0022FF50,ptr2-ptr1=2
18
19subtracting an int from a pointer:-------------------------------7
20ptr3=0022FF60,ptr3-2=0022FF58

解释:
------------------------------1
ptr1是一个int型的指针变量,里面存放的内容为数组urn的首地址,0022FF50;
*ptr1是urn首元素的值
ptr1本身是一个变量,所以有这个变量的地址,为0022FF4C。
------------------------------2
ptr1+4是指ptr1跳过4个int型,int型为4个字节,所以实际跳过16个字节,0022FF50跳过16个字节后为0022FF60.
ptr1+3实际为urn[3],为400
------------------------------3
ptr1++,实际为ptr1=ptr1+1,所以ptr1所指向的字节跳过1个int型,即跳过4个字节,为0022FF54.
这是*ptr1=urn[1],为200
虽然ptr1这个变量里面存放的数据会改变,但是ptr1本身变量的地址是不会变的。
------------------------------4
ptr2指向urn[2]这个元素,当--ptr2后,ptr2指向urn[1],urn的首地址为0022FF50,且ptr2==urn+1,所以为0022FF54.
ptr2变量本身的地址为&ptr2即0022FF48。
------------------------------5
恢复ptr1和ptr2
------------------------------6
ptr1与ptr2之间相差8个字节,又它们是int型的,一个int型占4个字节,所以ptr2-ptr1=2。
------------------------------7
同上。

10、对未初始化的指针取值
int *ptr;  //未初始化的指针
*ptr=5;    //一个可怕的错误
为什么这样的代码危害那么大?这段程序的第二行把数值5存放在ptr指向的内存单元,但是由于ptr没有初始化,所以它指向
的内存单元是随机的,有可能指向程序数据或代码的内存字节,赋值修改后很可能会是程序崩溃。切记:当创建一个指针时
,系统只分配了用来存储指针本身的内存空间,并不分配用来存储数据的内存空间。因此在使用指针之前,必须给它赋予一个已
分配的内存地址。

11、

 1#include<stdio.h>
 2int main()
 3{
 4    int *ptr3;
 5    int urn[5];
 6    int *ptr1,*ptr2;
 7    int i,j;
 8    i=1;
 9    j=2;
10
11    ptr1=&i;
12    ptr2=&j;
13
14    urn++;           //错误
15    ptr3=ptr1+ptr2;  //错误
16
17    return 0;
18}

19


11、有关const的内容
①指向常量的指针不能用于修改数值,如:
double rates[5]={1.0,2.0,3.0,4.0,5.0};
const double *pd=rates;
第二行代码把pd声明为指向const double的指针。这样就不可以用来使用pd来修改它所指向的单元的数值。
*pd=6;    //不合法
pd[2]=222.22;  //不合法
rates[0]=6;   //合法
rates并没有声明为常量,所以仍可以使用rates来修改其数值。另外,pd还可以指向其他地址:
pd++;    //合法
通常把指向常量的指针用作函数参量,以表明函数不会用这个指针来修改数据。如
void show_array(const double *ar,int n);
注意,将常量或非常亮数据的地址赋给指向常量的指针是合法的:
const double locked[4]={0.1,0.2,0.3,0.4};
pd=locked;   //合法
pd=rates;   //合法
然而只有非常量的地址才可以赋给普通的指针:
double *pnc=rates; //合法
pnc=locked;   //非法

②声明初始化指针,以保证指针不会指向别处,关键在于const的位置:
double *const pc=rates;  
pc=&rate[2];  //不允许
*pc=92.99;   //可以
这样的指针仍然可用来修改数据,但它只能指向最初赋给它的地址。

③使用两个const创建指针,这个指针既不可以更改所指向的地址,也不可以修改所指向的数据:
const double *const pdd=rates;
pc=&rates[2];  //不允许
*pc=92.99;   //不允许

12

 1#include<stdio.h>
 2int main()
 3{
 4    int zippo[4][2]={
 5        {1,2},{3,4},{5,6},{7,8}
 6    }
;
 7
 8    printf("zippo=%p,zippo[0]=%p,&zippo[0][0]=%p,&zippo[0]=%p\n",
 9            zippo,zippo[0],&zippo[0][0],&zippo[0]);
10    printf("zippo+1=%p,zippo[0]+1=%p\n",zippo+1,zippo[0]+1);
11
12    printf("*zippo=%p,*zippo+1=%p\n",*zippo,*zippo+1);
13    printf("zippo[0][0]=%d,*zippo[0]=%d,**zippo=%d\n",zippo[0][0],*zippo[0],**zippo);
14    printf("zippo[2][1]=%d,*(*(zippo+2)+1)=%d\n",zippo[2][1],*(*(zippo+2)+1));
15
16    return 0;
17}
显示结果为:
1zippo=0022FF50,zippo[0]=0022FF50,&zippo[0][0]=0022FF50,&zippo[0]=0022FF50
2zippo+1=0022FF58,zippo[0]+1=0022FF54
3*zippo=0022FF50,*zippo+1=0022FF54
4zippo[0][0]=1,*zippo[0]=1,**zippo=1
5zippo[2][1]=6,*(*(zippo+2)+1)=6

13、指向多维数组的指针
int (*pz)[2]; //pz为指针,指向一个含有2个元素的数组
int * pax[2]; //pax为数组,元素为2个int型指针
因为[]的优先级比*高。
如:
pz-------------[0]   
            |_____[1]          pax------指针[0]-------int数值
pz+1----------[0] 但是 pax+1----指针[1]-------int数值
            |_____[1]
pz+2----------[0]
            |_____[1]
  
例如:
 1#include<stdio.h>
 2int main()
 3{
 4    int zippo[4][2]={
 5        {1,2},{3,4},{5,6},{7,8}
 6    }
;
 7    int (*pz)[2];
 8    pz=zippo;
 9
10    printf("pz=%p,pz+1=%p\n",pz,pz+1);
11    printf("pz[0]=%p,pz[0]+1=%p\n",pz[0],pz[0]+1);
12    printf("*pz=%p,*pz+1=%p\n",*pz,*pz+1);
13    printf("pz[0][0]=%d,*pz[0]=%d,**pz=%d\n",pz[0][0],*pz[0],**pz);
14    printf("pz[2][1]=%d,*(*(pz+2)+1)=%d\n",pz[2][1],*(*(pz+2)+1));
15
16    return 0;
17}
显示结果为:
1pz=0022FF50,pz+1=0022FF58
2pz[0]=0022FF50,pz[0]+1=0022FF54
3*pz=0022FF50,*pz+1=0022FF54
4pz[0][0]=1,*pz[0]=1,**pz=1
5pz[2][1]=6,*(*(pz+2)+1)=6


假设有如下声明:
int *pt;
int (*pa)[3];
int ar1[2][3];
int ar2[3][2];
int **p2;
那么有如下结论:
pt=&art1[0][0];  //都指向int
pt=ar1[0];   //都指向int
pt=ar1;    //非法
pa=ar1;    //都指向int
pa=art2;   //非法
p2=&pt;    //都指向int
*p2=ar2[0]   //都指向int
p2=art2;   //非法

解释:
pt指向一个int数值,ar1指向由3个int值构成的数组,pa指向由3个int值构成的数组,ar2指向由2个int值构成的数组,p2是
指向int的指针的指针。ar1[0]和ar2[0]指向一个int数值,*p2指向一个int数值,&p1是一个指针的地址。

posted on 2011-03-10 16:40 八路 阅读(229) 评论(0)  编辑 收藏 引用 所属分类: C primer 易错点


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理