020-29133788
    资 讯
    您的位置:首页 >> 资 讯 >> 软件应用 >> 编程开发 >> 正文
    阵列及字串的教学

    点击:   发布日期:2013-01-19

    本文来自 www.020fix.com

    复制内容到剪贴板
    代码:
    之前再网路上搜集到的一份资料 是关于 阵列 还有字串的部份
    大家常有的 字串 转int ...等 或许可以参考上面的方法 解决
    [阵列及字串]
    简介
    为什要用阵列? 想像一下如果我们要写一个程式, 程式要求要输入全班同学的期中考数学科成绩, 写成程式会长什么样子?
    #include < stdio.h >
    void main(void)
    {
            int num1, num2, num3, num4, num5;
            scanf("%d",&num1);
            scanf("%d",&num2);
            scanf("%d",&num3);
            scanf("%d",&num4);
            scanf("%d",&num5);
    }

    上面的程式是全班只有5位学生时的情形, 那要是全班有50位学生时, 程式要怎么写? 这时就可求助于阵列(Array)
    #include < stdio.h >
    void main(void)
    {
            int i;
            int student[50];
           
            for ( i=0; i<50; i++ )
            {
                    scanf("%d", &student[i]);
            }
    }

    程式码明显的精简许多, 用原先的写法最少要宣告50个变数, 还要写50个scanf.
    使用#define的好处在这里就可以看出来.

    #include < stdio.h >

    #define STUDENTS 5

    void main(void)
    {
            int i;
            int student[STUDENTS];
            // 只要改define中STUDENTS的数值, 阵列大小和迴圈要跑的次数都会同时改变
            for ( i=0; i < STUDENTS; i++ )
            {
                    scanf("%d", &student[i]);
                    printf("I get %d\n",student[i]);
            }
    }

    简单的来说, 阵列就是一次宣告出许多个相同型态的变数来使用.
    int a[5];
    上面的语法会宣告出5个整数, 要取用阵列中的某个变数来用时, 要给一个索引值, 要取用这5个整数的方法分别是
    a[0]=1; // 把a[0]设定为1
    a[1]=2; // 把a[1]设定为2
    a[2]=3; // 把a[2]设定为3
    a[3]=4; // 把a[3]设定为4
    a[4]=5; // 把a[4]设定为5
    a[5]是不存在的.

    宣告大小为N时, 取用的索引值范围为0,1,2,.....N-1
    第二节:一维阵列的使用
    宣告阵列时, 同样一开始可以设定好它们的初值
    void main(void)
    {
            int a[5]={1,2,3,4,5};
            // 设定 a[0]=1, a[1]=2, a[2]=3, a[3]=4, a[4]=5
            int b[]={1,2,3};
            // 若size没指定, 因为给了3个数字, 在此会自动设定为b[3];
    }

    设定阵列时, 还常和迴圈一起使用
    void main(void)
    {
            int a[5];
            int i;
            for ( i=0; i<5; i++ )
            {
                    a[i]=i;
            }
            // 设定a[0]=0, a[1]=1, a[2]=2, a[3]=3, a[4]=4
    }

    读入5个数字, 求出它们的平均值.
    #include < stdio.h >

    #define NUM 5

    void main(void)
    {
            int i;
            float sum=0;
            float aver;
            float num[NUM];
           
            // 分别读入5个数值
            for ( i=0; i < NUM; i++ )
            {
                    scanf("%f", &num[i]);
            }
           
            // 计算总和
            for ( i=0; i < NUM; i++ )
            {
                    sum+=num[i];
            }
            // 求平均值
            aver=sum/(float)NUM;
            printf("average=%f\n",aver);
    }

    多维阵列
    使用阵列时,只用了一个索引值, 叫做一维阵列. 我们可以宣告出需要多个索引值的阵列来.
    void main(void)
    {
            int a[2][2];
            // 这时候, 有a[0][0], a[0][1], a[1][0], a[1][1]等4个变数可以使用
    }

    设定二维阵列初值的方法为
    void main(void)
    {
            int a[2][2]={ {00, 01},
                          {10, 11} };
            int b[2][2]={ 00,01,10,11 };
    }

    实实上, 阵列在记忆体中都是一块连续的记忆体空间. 一维阵列时很容易想像:
    int a[5];
    a[0]的位址是&a+0;
    a[1]的位址是&a+1;
    a[2]的位址是&a+2;
    a[3]的位址是&a+3;
    a[4]的位址是&a+4;

    二维阵列同样会是一块连续的记忆体空间
    int a[5][5];
    a[0][0]的位址是&a+0*5+0;
    a[0][1]的位址是&a+0*5+1;
    a[0][2]的位址是&a+0*5+2;
    .....
    a[1][1]的位址是&a+1*5+1;
    .....
    a[x][y]的位址是&a+x*5+y;
    结论
    int b[N][M];
    b[x][y]的位址是&b+x*M+y;
    int c[N][M][P];
    c[x][y][z]的位址是&c+x*M*P+y*P+z;

    范例:印出阵列中所有变数的记忆体位址
    #include < stdio.h >

    #define N 3
    #define M 2

    void main(void)
    {
            char a[N][M];
            for ( int i=0; i < N; i++ )
            {
                    for ( int j=0; j < M; j++ )
                    {
                            printf("%d\n",&a[i][j]);
                    }
            }
    }

    阵列的应用(1)
    范例:用一维阵列来储存向量, 把两个向量相加, 结果记录在另一个阵列中
    #include < stdio.h >
    #include < stdlib.h >
    #include < time.h >

    #define DIMENSION 3
    #define MAX_NUMBER 10

    void main(void)
    {
            int vector1[DIMENSION];
            int vector2[DIMENSION];
            int vector3[DIMENSION];
            int i;

            // 给定计算乱数的初值
            srand( time(NULL) );

            for ( i=0; i < DIMENSION; i++ )
            {
                    // 利用乱数来设定数值
                    vector1[i]=rand()%(MAX_NUMBER+1);
                    vector2[i]=rand()%(MAX_NUMBER+1);
            }
           
            // 印出vector1的内容
            printf("(");
            for ( i=0; i < DIMENSION; i++ )
            {
                    printf("%d ",vector1[i]);
            }
            printf(")+");
            // 印出vector2的内容
            printf("(");
            for ( i=0; i < DIMENSION; i++ )
            {
                    printf("%d ",vector2[i]);
            }
            printf(")=");

            // 计算并印出vector3的内容
            printf("(");
            for ( i=0; i < DIMENSION; i++ )
            {
                    vector3[i]=vector1[i]+vector2[i];
                    printf("%d ",vector3[i]);
            }
            printf(")\n");
    }

    范例:记录全班同学的考试成绩, 把低于60分不及格的同学号码印出来
    #include < stdio.h >
    #include < stdlib.h >
    #include < time.h >

    #define STUDENTS 30
    #define MAX_NUMBER 100

    void main(void)
    {
            int i;
            int student[STUDENTS];
            // 给定计算乱数的初值
            srand( time(NULL) );

            for ( i=0; i < STUDENTS; i++ )
            {
                    // 利用乱数来设定数值
                    student[i]=rand()%(MAX_NUMBER+1);
            }
           
            for ( i=0; i < STUDENTS; i++ )
            {
                    if ( student[i] < 60 )
                    {
                            printf("Student %d get %d points, fail!\n", i, student[i]);
                    }
            }
    }

    字串
    在程式语言中, 一个英文单字, 一个句子, 都可以当成一个字串. 简单的说, 要记录size超过一个字母的东西, 就叫做一个字串. 在C语言中, 一个一维的的字元阵列可以当成一个字串.
    #include < stdio.h >
    void main(void)
    {
            char a[]={"Hello"};
            printf("%s \n",a);
    }

    上面的写法, 相当于
    #include < stdio.h >
    void main(void)
    {
            char a[6];
            a[0]='H';
            a[1]='e';
            a[2]='l';
            a[3]='l';
            a[4]='o';
            a[5]='\0'; // a[5]=0; 0是字串的结束符号
            printf("%s \n",a);
    }

    或是
    #include < stdio.h >
    void main(void)
    {
            char a[6]={'H','e','l','l','o','\0'};
            printf("%s \n",a);
    }

    利用scanf来读取一个字串的方法如下
    #include < stdio.h >
    void main(void)
    {
            char a[80];
            scanf("%s",a);
            printf("%s \n",a);
    }

    用scanf来读字串, 字串中不能有空白. 若有空白会被当成两个不同的字串. 要读取有空白的字串要用gets;
    #include < stdio.h >
    void main(void)
    {
            char a[80];
            gets(a);
            printf("%s \n",a);
    }

    字串不能直接互相做比对, 下面的程式是没有意义的
    #include < stdio.h >

    void main(void)
    {
            char a[]="Hello";
            char b[]="How are you";
            // 下面的比较会变成 &a 和 &b 这两个位址互相去比较
            if ( a==b )
            {
                    printf("a==b\n");       
            }
    }

    比较字串要用C的库存函式strcmp
    #include < stdio.h >
    #include < string.h >
    void main(void)
    {
            char a[]="Hello";
            char b[]="How are you";
            if ( strcmp(a,b)==0 )
            {
                    printf("a==b\n");       
            }
            else
            {
                    printf("a!=b\n");
            }       
    }

    定义在string.h中经常使用的函式有 函式名称  用途  
    strcpy  copy字串  
    strcat  把一个字串插到另一个字串的后面  
    strlen  计算字串的长度  

    范例:

    #include < stdio.h >
    #include < string.h >
    void main(void)
    {
            char a[80]="Hello,";
            char b[]=" how are you?";
            char c[80];
            strcat(a,b);
            printf("%s\n",a);
            strcpy(c,a);
            printf("%s\n",c);
            printf("%d\n", strlen(c) );
    }

    字串应用(1)
    范例:把一个字串反过来
    #include < stdio.h >
    #include < string.h >

    #define MAX_STRING 80

    void main(void)
    {
            char a[MAX_STRING];
            char b[MAX_STRING];
            int  len;
            int  i,j;
           
            gets(a);
            len=strlen(a);

            for ( i=0, j=len-1; i < len; i++, j-- )
            {
                    b[j]=a[i];
            }
            b[len]='\0';
            printf("%s \n",b);
    }

    范例:把字串中的空白字元都拿掉
    #include < stdio.h >
    #include < string.h >

    #define MAX_STRING 80

    void main(void)
    {
            char a[MAX_STRING];
            char b[MAX_STRING];
            int  len;
            int  i,j;
           
            gets(a);
            len=strlen(a);

            for ( i=0, j=0; i <= len; i++ )
            {
                    if ( a[i]!=' ' )
                            b[j++]=a[i];
            }
            printf("%s \n",b);
    }

    另一种解法
    #include < stdio.h >
    #include < string.h >

    #define MAX_STRING 80

    void main(void)
    {
            char a[MAX_STRING];
            int  len;
            int  i,j;
           
            gets(a);
            len=strlen(a);

            for ( i=0, j=0; i < len; i++ )
            {
                    if ( a[i]!=' ' )
                            a[j++]=a[i];
            }
            a[j]='\0';
            printf("%s \n",a);
    }

    第五节:字串进阶
    如果字串当中的字元都是数字, C的库存函式中有提供把字串转换回数字的函式.
    #include < stdio.h >
    #include < stdlib.h >
    void main(void)
    {
            char string[]="100";
            char string2[]="0.5";
            int  num;
            double num2;
            num=atoi(string);
            // 函式atoi可以把字串换算成整数
            num2=atof(string2);
            // 函式atof可以把字串换算成浮点数
            printf("%d %lf\n",num,num2);
    }

    用sscanf也可以做到同样的效果
    #include < stdio.h >
    #include < stdlib.h >
    void main(void)
    {
            char string[]="100";
            char string2[]="0.5";
            int  num;
            double num2;
            sscanf(string,"%d",&num);
            sscanf(string2,"%lf",&num2);
            // sscanf和scanf用法一样, 只是输入的来源改成从字串中读取而不是从键盘
            printf("%d %lf\n",num,num2);
    }

    相对地, 数字也可以反回去转成字串, 这要用sprintf来做到.
    #include < stdio.h >
    #include < stdlib.h >
    void main(void)
    {
            char string[80];
            int  num=5;
            float fnum=0.5;
            sprintf(string,"num=%d fnum=%f",num,fnum);
            // sprintf的用法和printf完全相同,
            // 只是printf把结果印在萤幕上, sprintf把结果印到一个字串中.
            printf("%s\n",string);
    }

    atoi及atof函式本身的运作原理很简单, 其实就是一个一个字元去把数字算出来而已. 下面是一个简单的atoi函式的过程.
    // 模拟atoi函式的运作
    #include < stdio.h >
    #include < stdlib.h >
    #include < string.h >

    void main(void)
    {
            char string[80];
            int  i;
            int         len;
            int  num;

            gets(string);
            len=strlen(string);

            num=0;
            for ( i=0; i < len; i++ )
            {
                    num*=10;
                    num+=string[i]-'0';
            }
            printf("%d\n",num);
    }

    sprintf的原理也是一个一个数字把它再换回去成为字元而已, 下面是一个把数字转回字串的程式
    #include < stdio.h >
    #include < stdlib.h >
    #include < string.h >

    void main(void)
    {
            char string[80];
            char temp;
            int  i,j;
            int  len;
            int  num;
            scanf("%d",&num);
            len=0;
            do
            {
                    string[len++]='0'+num%10;
                    num/=10;
            }while(num>0);
            string[len]='\0';
            // 字串反转
            for ( i=0, j=len-1; i < len/2; i++,j-- )
            {
                    temp=string[j];
                    string[j]=string[i];
                    string[i]=temp;
            }
            printf("%s\n",string);
    }

    为什么会需要用到sprintf?有很多情形下, 不会使用到printf来做输出. 像是在视窗作业系统开启一个Message Box来显示讯息. 此时就需要先把需要输出的数字都转成字串, 再透过WIN32 API 函式来秀出讯息.
    范例:开启一个MessageBox来显示计算求得的正方形面积
    #include < stdio.h >
    #include < windows.h >
    void main(void)
    {
            char string[80];
            int  r;
            int  area;
            scanf("%d",&r);
            area=r*r;
            sprintf(string,"Area=%d",area);
            MessageBox(NULL,string,"Hello",MB_OK);
            // Win32 API之一, 会开启一个简单的message box, 印出第2个参数的字串内容
    }

    那为什么需要用到atoi/atof?用scanf来读键盘时,使用者可能会输入错误. 例如说要输入数字却输入字元. 比较好的方法就是scanf中读进去的东西都先把它当成字串, 检查字串中有没有不合理的东西出现. 不合理就要求重新输入, 合理的话才把字串转成数字.
    #include < stdio.h >
    #include < stdlib.h >
    #include < string.h >

    void main(void)
    {
            char string[80];
            int  num;
            int  len;
            while(1)
            {
                    printf("Please input an integer:");
                    scanf("%s",string);
                    // 检查字串中有没有不是数字的字元出现
                    len=strlen(string);
                    for ( int i=0; i < len; i++ )
                    {
                            if ( string[i] < '0' || string[i] > '9' )
                                    break;
                    }
                    // 如果每个字元都是'0','1',...'9'当中的任一个, 就跳出迴圈
                    if ( i==len )
                            break;
            }
            num=atoi(string);
            printf("I get %d\n",num);
    }