C语言速成手册(三):数组、字符串、结构

一维数组的定义、初始化和使用
    定义一个一维数组的格式如下:
类型 数组名[数组大小];
    数组的下标范围总是从0开始(因此下标最大为数组大小减一)。下面一行语句定义了一个大小为10的长整型数组:
long value[10];
    这相当于下面的Pascal语句:
var value:array[0..9]of longint;
    C语言的数组范围左端点不能自定义,它的数组下标只能从0开始。

    下面几种方式可以在定义数组的同时进行初始化:
long value[10] = { 0, 8, 2, 0, 3 } ;
long value[10] = { [1]=8, [2]=2, [4]=3 } ;
    上面两个语句是等价的。其中前一种方法依次对数组的前5个数进行初始赋值,后一种方法仅对数组的其中三个位置进行初始化。初始化中没有涉及到的下标所对应的数值自动被设为0。
    C语言允许数组的大小为一个变量,但这样的数组在定义时不能像上面一样进行初始化。
    这种初始化方法只在定义数组时用,不能用于程序中的赋值。数组之间也不能直接赋值,你不能把数组a整个赋值给数组b。

    程序中使用数组的方法和Pascal一样。下面的程序将输出1000以内的素数:
#include <stdio.h>
#include <stdbool.h>
int main()
{
   bool isPrime[1000];
   int i,j;
  
   for(i=2;i<1000;i=i+1)
      isPrime[i]=true;
      
   for(i=2;i<1000;i=i+1)
   {
      if (isPrime[i])
      {
          printf("%d ",i);
          for(j=2*i;j<1000;j=j+i)
             isPrime[j]=false;  
      }
   }
  
   return 0;
}

    当一维数组作为函数参数时,数组大小可以不写,以适应不同长度的数组。通常你还需要另一个参数告诉函数你的数组有多大。下面这个函数返回数组中的最大值:
long maxValue ( long length, long array[] )
{
   long i, max = 0;
   for ( i=0; i<length; i=i+1)
      if (array[i]>max) max = array[i];
   return max;
}

    下面的代码合法地调用了上面的函数。
long a[5] = { 1, 5, 7, 3, 4 };
printf( "%d" , maxValue( 5,a ) );



C语言中的字符串
    C语言也使用字符数组作为字符串。定义一个char a[20],就相当于定义了一个长度不超过20的字符串。Pascal中使用a[0]记录字符串的长度,字符串内容从a[1]开始;但C语言并不直接记录字符串长度,a[0]表示字符串的第一个字符,最后以ASCII码0(或写成字符'/0')标记字符串结尾。你可以直接将一个字符串赋给字符数组,也可以在printf中使用%s标识输出一个字符数组。记住,a[2]表示字符串中的第三个字符,因为C的数组下标是从0开始的。
    观察下列代码:
int i;
char a[20]="matrix67.com";

for (i=0;i<20;i=i+1)
   printf("%d ",a[i]);
printf("/n%c/n",a[2]);
printf("%s/n",a);
printf("%16s/n",a);
printf("%.8s/n",a);
printf("%16.8s/n",a);

    程序的输出为:
109 97 116 114 105 120 54 55 46 99 111 109 0 0 0 0 0 0 0 0
t
matrix67.com
    matrix67.com
matrix67
        matrix67

    == 或 + 等运算符对字符串无效。

    下面的函数返回字符串的字符数:
int stringLength( char a[] )
{
   int count=0;
   while ( a[count] )
      count=count+1;
   return count;
}


    赋值时,如果字符串太长了,有两种方法可以让你分行写。一是在行末加一个反斜杠表示和下一行相连,二是每一行都用双引号注明(编译器会自动把它连接起来)。下面两个代码是等价的。注意第一个代码中的第二行必须顶格写,否则第二行前面的空格也要算进字符串里。
char blogTitle[100]="Matrix67: My Blog - 50% Informatics, 50% /
Mathematics, and 50% Imagination";

char blogTitle[100]="Matrix67: My Blog - 50% Informatics, 50% "
                 "Mathematics, and 50% Imagination";


    和数组一样,对字符串的赋值只能在定义时使用,程序中不能这样做。


多维数组的定义、初始化和使用
    定义一个多维数组的格式如下:
类型 数组名[大小1][大小2]...[大小n];
    例如,下面这个语句定义了一个三维数组:
int matrix[100][100][2];
    同样地,每一维的大小都是从0开始算的。因此上面的语句相当于Pascal中的:
var matrix:array[0..99][0.99][0..1]of integer;

    多维数组的初始化和一维数组类似。例如,我们经常需要定义方向常量:
const int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
    这还可以直接写成:
const int dir[4][2] = { 1, 0, 0, 1, -1, 0, 0, -1 };
    多维数组的初始化同样是未定义者自动填零,因此还可以写成:
const int dir[4][2] = { [0][0]=1, [1][1]=1, [2][0]=-1, [3][1]=-1 };

    程序中使用多维数组时必须用多个方括号,即dir[2][1]不能写成dir[2,1]。

    当多维数组作为函数的参数时,只有第一维的大小可以不写。因此,下面的三个函数中前两个是合法的,第三个是不合法的。
long function_1( int m, int n, long a[20][20] );
long function_2( int m, int n, long a[][20] );
long function_3( int m, int n, long a[][] );

    为了让参数仍然适用于各种大小的数组,C语言允许这样定义函数:
long function_4( int m, int n, long[m][n] );
    例如,下面的函数递归地计算行列式:
long determinant( int n, long a[n][n] )
{
    if (n==1) return(a[0][0]);
    
    int i,j,k;
    long ans = 0;
    long sub[n-1][n-1];
    
    for ( i=0; i<n; i=i+1 )
    {
        for ( j=1; j<n; j=j+1 )
        {
           for ( k=0; k<i; k=k+1 )
              sub[j-1][k]=a[j][k];
           for ( k=i+1; k<n; k=k+1 )
              sub[j-1][k-1]=a[j][k];
        }
        ans = ans + (1-i%2*2)*a[0][i]*determinant(n-1, sub);
    }
    return ans;    
}

    下面的代码片段正确地调用了上面的函数:
long a[4][4]={
               { 1, 4, -1,  4 },
               { 2, 1,  4,  3 },
               { 4, 2,  3, 11 },
               { 3, 0,  9,  2 }
             };
printf( "%d" , determinant(4,a) );


结构的定义、初始化和使用
    Pascal中的记录类型在C语言中叫做“结构”。定义一个结构的方式如下:
struct 结构名
{
   在此定义若干变量(域)
};

    注意花括号后面需要有一个分号。下面定义一个date结构:
struct date
{
   int year;
   short month,day;
};

    这样你就获得了一个名为struct date的类型名。和变量的定义一样,一个结构的定义只能供当前函数(的当前语句块)中后面的部分使用。因此通常把结构的定义放在所有函数的前面作为一个全局的定义。之后,你便可以写这样的语句:
struct date today;

    结构的使用方法同Pascal的记录类型一样。例如,下面的函数用于计算某一天是星期几(Zeller公式):
int zeller( struct date t )
{
   if (t.month<3)
   {
      t.year = t.year - 1;
      t.month = t.month + 12;
   }
   int c = t.year / 100;
   int y = t.year % 100;
   int ans = ( c/4 - 2*c + y + y/4 + (26*(t.month+1))/10 + t.day - 1 ) % 7;

   if (ans>0) return ans;
   else return ans+7;
}


    给一个结构赋初始值和数组的初始化差不多。下面两个语句是等价的:
struct date myBirthday = { 1988, 5, 16 };
struct date myBirthday = { .year=1988, .month=5, .day=16 };
    这种方法也可以用于程序中的赋值操作,但需要加上一个类型转换(见这里的“名词动用”一节)。例如,下面三个代码片段都是等价的:
myBirthday.year = 1988;
myBirthday.month = 5;
myBirthday.day = 16;

myBirthday = (struct date){ .year=1988, .month=5, .day=16 };
myBirthday = (struct date){ 1988, 5, 16 };
    下面的语句调用了zeller函数,输出自1583年来的每个13日都是星期几。和本文无关的问题:有人知道为什么我从1583年开始算么?
int y,m;
for ( y=1583; y<=2000; y=y+1)
   for ( m=1; m<=12; m=m+1 )
      printf( "%d ", zeller( (struct date){y,m,13} ) );


Matrix67原创
转贴请注明出处

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值