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(或写成字符'')标记字符串结尾。你可以直接将一个字符串赋给字符数组,也可以在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%cn",a[2]);
printf("%sn",a);
printf("%16sn",a);
printf("%.8sn",a);
printf("%16.8sn",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原创
转贴请注明出处

17 条评论

  • windywinter

    const int dir[4][2] = { [1][1]=1, [2][2]=1, [3][1]=-1, [4][2]=-1 };
    里面的[4][2]是给谁赋值?

    回复:谢谢指正,已改正

  • yiyi

    1582.10.4的下一天ms是1582.10.15.
    似乎可以用"int ans = ( c/4 – 2*c + y + y/4 + (26*(t.month+1))/10 + t.day + 3 ) % 7;"来算此前的.

    回复:不行,这之前的历法不同

  • axgle

    我的c语言都要忘光了,重温一下.
    "结构的定义、初始化和使用"很不错,正是我需要的.

  • Prince_Arthur

    int c = t.year / 100;
    c如果是世纪的话,算出来应该要加1吧.

  • OliverQ

    i = i + 1;
    j = j + 1;
    y = y + 1;
    m = m + 1;
    ……
    这是C语言写的程序么?i++更方便

  • 小白

    请问,怎么能让字符串数组=0。

  • menie

    “定义一个char a[20],就相当于定义了一个长度不超过20的字符串。”

    应该是长度不超过21吧?

  • menie

    哦,还得留下放n的地方。。

  • cbk

    1583是是什么啊好奇~

  • 忍的阵雨

    long function_4( int m, int n, long[m][n] );
    错了吧,应为
    long function_4( int m, int n,long a[m][n] );

  • lololi

    罗马教皇格里高利十三世在1582年组织了一批天文学家,根据哥白尼日心说计算出来的数据,对儒略历作了修改。将1582年10月5日到14日之间的10天宣布撤销,继10月4日之后为10月15日。

  • liuzitan

    C语言也使用字符数组作为字符串。定义一个char a[20],就相当于定义了一个长度不超过20的字符串。

    ==============================
    不对吧?访问数组越界!!!
    直接段错误。
    char a[20] 有十九个字符([0] ~ [18]),一个”([19])

    望改正

  • lcq

    菜鸟提问——long value[10] = {[1]=8, [2]=2, [4]=3} ;
    用这种格式为什么报错:
    79 H:c++DEV-CPPprog1.cpp expected primary-expression before ‘[‘ token

  • cervelo

    不对吧?访问数组越界!!!
    直接段错误。

  • sunchy321

    @14L
    这种定义方式在ANSI里没有实现。。。

  • 小鹰

    行列式函数的for j应该是0开始吧

发表评论

5  ×    =  45