zoukankan      html  css  js  c++  java
  • C:数组

     

    与字符串处理有关的函数:

    头文件:<stdio.h>    gets()、puts()

    头文件:<string.h>

    (1)、字符串长度测量函数  :strlen(字符数组名),返回一个整型值:字符串中的实际字符数(不包括 '')

    (2)、字符串赋值函数:strcpy(字符数组名1,字符串2),将字符串2的所有字符一个一个复制到字符数组中,直到遇到结束标志 ''为止,并将结束标识符也写入字符数组1中

                  指定数量的字符串赋值函数:strncpy(字符数组1,字符数组2,要复制的字符个数)

    (3)、字符串连接函数:strcat(字符数组1,字符串2),取消第一个字符数组的字符串的结束标志 '' ,把第二个字符串拼接至第一个字符串后面,并把拼接的结果存放到第一个字符数组中

    (4)、字符串比较函数 :strcmp(字符串1,字符串2),按字典排序进行比较,即从字符串1和字符串2的第一个字符开始从左至右依次按照 ASCII码 进行比较,直到出现不相同的字符或者碰到结束标志 '' 为止,以第一个不相等的字符的比较结果作为整个字符串的比较1结果:

           字符串1和字符串2相等,即长度相同,对应的字符也相同,返回0

        字符串1大于字符串2,则返回一个正整数

        字符串1小于字符2.则返回一个负整数

    (5)、查找字符2在字符串1中第一次出现的位置:strchr(字符串1,字符2)

    (6)、找到字符串2在字符串1中第一次出现的位置:strstr(字符串1,字符串2)

    二维数组:

    void main()
    {
        int i;
        int a[5][10];
        for(i = 0;i < 5;i++)
        {
            gets(a[i]);
        }
        printf("
    %s",a); //  a = a[0]
    }

    1、求200以内的所有的素数

    算法分析:

    采样筛选法:

    (1)、取最小的数2,并声明它是素数,同时筛去它及它的所有倍数

    (2)、取未被筛去的数中最小者,声明它是素数,同时筛去它及它的所有倍数

    (3)、重复步骤(2),至筛中无数为至,得到所有的素数

    本例可使用数组,使数组下标就是200以内的数,让数组元素的值作为筛去与否的标志,这里设数组元素的初值为0,筛去以后就是1

    为提高筛选效率:

      一个合数n必有一个不大于sqrt(n)的正因子,故一个数若是没有小于sqrt(n)的正因子,则说明它是一个素数

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    void main()
    {
        int prime[201] = {0};  // 已筛去的值为1.未筛去的值为0
        int d;
        int k;
        int i;
    
        for(d = 2;d <= sqrt(200);d++)
        {
            if(prime[d] == 0)
            {
                for(k = 2*d;k <= 200;k = k + d)
                {
                    prime[k] = 1;  // 筛去d的所有倍数
                }
            }
        }
    
        k = 0;
        for(i = 2;i <= 200;i++)
        {
            if(prime[i] == 0)
            {
                printf("%d	",i);
                k++;
                //一行输出5个数
                if(k % 5 == 0)
                {
                    printf("
    ");
                }
            }
        }
    }
    

    2、将由6个整数组成的序列,将其按从大到小的顺利排列

    算法分析:使用冒泡排序法【对于n个数排序,至多进行n-1 遍排序,每遍进行n-i 次比较】

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    const int n = 6;
    
    void main()
    {
        int a[n];
        int i;
        int j;
        int temp;
    
        //输入
        printf("请输入待排序元素:
    ");
        for(i = 0;i < n;i++)
        {
            printf("a[%i]=",i);
            scanf("%d",&a[i]);
        }
    
        //排序
        for(i = 1;i < n;i++)
        {
            for(j = 0;j < n-i;j++)
            {
                if(a[j] < a[j+1])
                {
                    temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                }
            }
        }
    
        //输出
        printf("排序后从大到小输出:
    ");
        for(i = 0;i < n;i++)
        {
            printf("%d	",a[i]);
        }
        printf("
    ");
    }
    

    由于对什么样的数据都会扫描n-1遍,包括已经排好序的也会扫描n-1遍

    改进:设置一个变量change 表示一遍扫描中是否会进行交换,在每一遍扫描开始时,将其设置为,表示未交换;在扫描中如果进行了交换,则将变量设置为1,本遍扫描完成后,如果change=0,则表示本遍扫描中未进行交换,即可退出扫描。

    代码:

    //改进
    void main()
    {
        int a[n];
        int i;
        int j;
        int temp;
        int change;
    
        //输入
        printf("请输入待排序元素:
    ");
        for(i = 0;i < n;i++)
        {
            printf("a[%i]=",i);
            scanf("%d",&a[i]);
        }
    
        //排序
        for(i = 1;i < n;i++)
        {
            change = 0;
            for(j = 0;j < n-i;j++)
            {
                if(a[j] < a[j+1])
                {
                    temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                    change = 1;
                }
            }
            if(change = 0)
            {
                break;
            }
        }
    
        //输出
        printf("排序后从大到小输出:
    ");
        for(i = 0;i < n;i++)
        {
            printf("%d	",a[i]);
        }
        printf("
    ");
    }
    

    直接插入法实现:

    //直接插入法实现
    void main()
    {
        int a[n];
        int i;
        int j;
        int temp;
    
        //输入
        printf("请输入待排序元素:
    ");
        for(i = 0;i < n;i++)
        {
            printf("a[%i]=",i);
            scanf("%d",&a[i]);
        }
    
        //排序
        for(i = 1;i < n;i++)
        {
            j = i - 1;
            temp = a[i];
            while((a[j] < temp) && (j >= 0))
            {
                a[j + 1] = a[j];
                j--;
            }
            a[j + 1] = temp;
        }
    
        //输出
        for(i = 0;i < n;i++)
        {
            printf("%d	",a[i]);
        }
        printf("
    ");
    }
    

    直接插入法改进:

    //直接插入法实现改进
    void main()
    {
        int a[n];
        int i;
        int j;
        int change;
        int temp;
    
        //输入
        printf("请输入待排序元素:
    ");
        for(i = 0;i < n;i++)
        {
            printf("a[%i]=",i);
            scanf("%d",&a[i]);
        }
    
        //排序
        for(i = 1;i < n;i++)
        {
            j = i - 1;
            temp = a[i];
            change = 0;
            while((a[j] < temp) && (j >= 0))
            {
                a[j + 1] = a[j];
                j--;
                change = 1;
            }
            a[j + 1] = temp;
            if(change = 0)
            {
                break;
            }
        }
    
        //输出
        for(i = 0;i < n;i++)
        {
            printf("%d	",a[i]);
        }
        printf("
    ");
    }
    

    3、

    算法分析:采样直接插入法进行排序

    (1)、用数组a存储待排序元素,n存储待排序元素的个数

    (2)、让 i 表示排序的遍数,其值为从2到n

    (3)、在每趟排序中,a[1],a[2],a[3]。。。,a[i-1] 已经排好序,以a[0] 为监视哨,将a[i]依次与a[i-1],a[i-2],.............,a[0]比较,即令循环变量j = i -1, i - 2, .... , 0 

    (4)、如果a[0] < a[j] ,则将a[j] 后移,否则终止此循环

    (5)、将a[j + 1]的值赋为a[o]

    #include <stdio.h>
    #include <stdlib.h>
    
    void main()
    {
        static int a[] = {23,56,234,1,45,34,21,394,3,35};
        int i,j,temp;
    
        //排序
        for(i = 1;i < 10;i++)
        {
            j = i - 1;
            temp = a[i];   //前面i-1个元素已经排好序
            while((a[j] > temp) && (j >= 0))
            // 把前面i-1个元素中比a[i]大的元素依次后移
            {
                a[j + 1] = a[j];
                j--;
            }
            a[j + 1] = temp;   // 把a[i]插入到正确的位置
        }
    
        //输出
        for(i = 0;i < 10;i++)
        {
            printf(" %d",a[i]);
        }
        printf("
    ");
    }
    

    改进:使用a[0] 作为监视哨,免去查找过程中每一步都要检测的数组是否越界的问题

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    const int n = 10;
    
    //改进
    void main()
    {
        int a[n+1];
        int i,j;
        //输入
        for(i = 1;i <= n;i++)
        {
            printf("请输入待排序数a[%d]:",i);
            scanf("%d",&a[i]);
        }
        //排序
        for(i = 2;i <= n;i++)
        {
            a[0] = a[i];
            for(j = i - 1;a[0] < a[j];j--)
            {
                a[j + 1] = a[j];
            }
            a[j + 1] = a[0];
        }
        //输出
        for(i = 1;i <= n;i++)
        {
            printf("%d	",a[i]);
        }
    }

    4、将英语规则名词有单数变为复数,规则如下:

    (1)、以字母y结尾,且y前面是一个辅音字母,则将y 变 i ,再加es;

    (2)、以s、x、ch、sh结尾,则加es

    (3)、以字母o结尾,则加es

    (4)、其他情况直接加s

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void main()
    {
        char word[100];
        int len;
        printf("请输入一个单词:");
        scanf("%s",word);
        len = strlen(word);  //求单词长度
    
        // 若以y结尾
        if((len > 1) && (word[len - 2] != 'a') && (word[len - 2] != 'e') && (word[len - 2] != 'i') && (word[len - 2] != 'o') && (word[len - 2] != 'u') && (word[len - 1] == 'y'))
        {
            word[len - 1] = 'i';
            word[len] = 'e';
            word[len + 1] = 's';
            word[len + 2] = '';
        }
        //若以s、x、ch、sh结尾
        else if((word[len - 1] == 's') || (word[len - 1] == 'x') || (len > 1 && word[len - 1] == 'h' && (word[len - 2] == 'c' || word[len - 2] == 's')))
        {
             word[len] = 'e';
             word[len + 1] = 's';
             word[len + 2] = '';
        }
        //以o结尾
        else if(word[len - 1] == 'o')
        {
              word[len] = 'e';
              word[len + 1] = 's';
              word[len + 2] = '';
        }
        //其他方式结尾
        else
        {
            word[len] = 's';
            word[len + 1] = '';
        }
        printf("单词的复数形式为:%s
    ",word);
    }
    

    5、明文变密文:

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void main()
    {
        char str1[200]; //存储明文
        char str2[200];  //存储密文
        int num;
        int len = 0;
        int i;
        //输入明文
        printf("请输入明文:");
        gets(str1);
        //求明文长度
        len = strlen(str1);
    
        for(i = 0;i < len;i++)
        {
            num = -1;  //初始化字母序列
            //处理小写字母
            if(str1[i] <= 'z' && str1[i] >= 'a')
            {
                num = str1[i] - 'a' + 1;
                num = num * 3 % 52;
            }
            //处理大写字母
            else if(str1[i] <= "Z" && str1[i] >= "A")
            {
                num = str1[i] - 'A' + 27;
                num = num *3 % 52;
            }
            //密文为小写字母
            if(num > 0 && num <= 26)
            {
                str2[i] = num + 'a' - 1;
            }
            //密文为大写字母
            else if(num >= 27 && num <= 51)
            {
                str2[i] = num +'A' - 27;
            }
            //密文为Z
            else if(num == 0)
            {
                str2[i] = 'Z';
            }
            //密文为其他字符
            else
            {
                str2[i] = str1[i];
            }
        }
        //为密文加上结束标志
        str2[i] = '';
        printf("密文是:%s
    ",str2);
    }
    

    6、【查找】

     

    (1)、从前向后依次查找

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    const int n = 7;
    
    void main()
    {
        int a[n + 1];
        int i,j,x;
        //输入
        for(i = 1;i <= n;i++)
        {
            printf("请输入a[%d]:",i);
            scanf("%d",&a[i]);
        }
        printf("请输入待查元素:");
        scanf("%d",&x);
        //查找
        for(i = 1;i <= n;i++)
        {
            if(a[i] == x)
            {
                break;
            }
        }
        if(i <= n)
        {
            printf("%d
    ",i);
        }
        else
            printf("%d
    ",0);
    }
    

    (2)、从后向前,依次查找,故结束后不必对i的值进行比较

    代码:

    void main()
    {
        int a[n + 1];
        int i,j,x;
        //输入
        for(i = 1;i <= n;i++)
        {
            printf("请输入a[%d]:",i);
            scanf("%d",&a[i]);
        }
        printf("请输入待查元素:");
        scanf("%d",&x);
        //查找
        for(i = n;i >= 1;i--)
        {
            if(a[i] == x)
            {
                break;
            }
        }
        printf("%d
    ",i);
    }
    

    (3)、使用监视哨 ,免去查找过程中每一步都要检测的数组是否越界的问题

     代码:

    void main()
    {
        int a[n + 1];
        int i,j,x;
        //输入
        for(i = 1;i <= n;i++)
        {
            printf("请输入a[%d]:",i);
            scanf("%d",&a[i]);
        }
        printf("请输入待查元素:");
        scanf("%d",&x);
        //查找
        a[0] = x;  //若到i = 0时,退出循环,i = 0
        for(i = n;a[i] != x;i--);
        printf("%d
    ",i);
    }
    

    (4)、折半查找  【必须为有序数组】

    算法思想:

     

     代码:

    void main()
    {
        int a[n + 1];
        int i,x,low = 1,high = n,mid;
        //输入
        for(i = 1;i <= n;i++)
        {
            printf("请输入有序数字a[%d]:",i);
            scanf("%d",&a[i]);
        }
        printf("请输入待查元素:");
        scanf("%d",&x);
        //查找
        while(low <= high)
        {
            mid = (low + high) / 2;
            if(x == a[mid])
                break;
            else if(x < a[mid])
                high = mid - 1;
            else
                low = mid + 1;
        }
        //输出
        if(x == a[mid])
        {
            printf("%d
    ",mid);
        }
        else
            printf("%d
    ",0);
    }
    

    7、写一个函数,使其能将一个二维数组(5×3)中的数据进行行列互换(参考函数 原型:void tran(int array[5][3]))

     代码:

    #include <stdio.h>
    #include <stdlib.h>
    int b[3][5];   //外部二维数组,可以被全部函数访问
    
    void tran(int array[5][3])//定义转秩函数,无返回值
    {
        int i,j;
        for(i=0; i<5; i++)
            for(j=0; j<3; j++)
                b[j][i]=array[i][j];//交换
    }
    main()
    {
        int i,j;
        int a[5][3]= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        printf("交换前是:
    ");
        for(i=0; i<5; i++)
        {
            for(j=0; j<3; j++)
                printf("%4d",a[i][j]);
            printf("
    ");
        }
        tran(a);//调用交换函数实现对数组 a 的转秩
        printf("
     交换后是:
    ");
        for(i=0; i<3; i++)
        {
            for(j=0; j<5; j++)
                printf("%4d",b[i][j]);
            printf("
    ");
        }
    }
    

    8、写一个函数,使其能统计主调函数通过实参传送来的字符串,对其中的字母、数字和空格分别计数(要求在主函数中输入字符串及输出统计结果)(参考函数原型:void count(char* str))

     代码:

    #include <stdio.h>
    #include <stdlib.h>
    int b[3];  //定义外部变量,用于存储各种字符的个数
    
    void count(char *str)//定义统计函数
    {
        while((*str)!=0)
        {
            if(('a'<=*str&&*str<='z')||('A'<=*str&&*str<='Z'))//求字符个数
                b[0]++;
            if('0'<=*str&&*str<='9')//求数字个数
                b[1]++;
            if(*str==' ')//空格个数
                b[2]++;
            str++;
        }
    }
    void main()
    {
        char str[100];
        printf("请输入字符串:
    ");
        gets(str);
        printf("字符串%s 中",str);
        count(str);//调用统计函数
        printf("
     字母个数:%d",b[0]);
        printf("
     数字个数:%d",b[1]);
        printf("
     其空格个数:%d",b[2]);
    }
    

    程序分析:

      定义了一个外部数组变量 b[3]用于存储各种字符的个数。
    外部变量可以被全部函数共同访问,所以就不需要在统计函数和主函数中分开定义各自的统
    计变量,更加方便和节省空间

    9、写一个函数,使其能处理字符串中除字母(大小写)、数字外的其他 ASCII 字符,对多于一个连在一起的相同字符,将其缩减至仅保留一个。(参考函数原型:void del(char*str))

    算法分析:

      难点在于处理连在一起的相同字符。首先定 义一个字符数组 str2[ ],用于存储判断处理后的字符串。字符串 str 开始循环后,如果是字母或者数字,就赋给 str2;如果是其他字符,先判断是否为连续,再进行赋值。连续的情况需要特殊处理,循环直到是其他字符后再赋值。

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    char str2[80];//定义一个数组存储字符串
    
    void del(char *str)//定义函数
    {
        int i=0;
        while((*str)!=0)
        {
            if(('a' <= *str && *str <= 'z')||('A' <= *str && *str <= 'Z')||('0' <= *str && *str <= '9'))//判断 ASCII 码
            {
                str2[i]=*str;
                str++;
                i++;
            }
            else//处理连在一起的相同其他字符
            {
                while(*str==*(str+1))
                    str++;
                str2[i]=*str;
                str++;
                i++;
            }
        }
    }
    void main()
    {
        char str[80];
        printf("请输入字符串:");
        gets(str);
        del(str);
        printf("
    新字符串:%s
    ",str2);
    }
    

    10、设有一个 3 位数,将它的百、十和个位 3 个单一数,各自求立方,然后加起来,正好等于这个 3 位数,如 153=1+125+27。写一个函数,找出所有满足条件的数。(参考函数原型:int find(int n))

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    int find(int n)
    {
        int i,j,k; //i 表示百位,j 表示十位,k 表示个位
        int flag; //标志位,是否满足条件
        i = n / 100; //求百位
        j = n / 10 - i * 10; //求十位
        k = n % 10; //求个位
        if(n == i * i * i + j * j * j + k * k * k) //判断
            flag = 1;
        else
            flag = 0;
        return flag;
    }
    void main()
    {
        int f,n;
        printf("符合条件的数有:");
        for(n = 100; n < 1000; n++) //循环判断所有的三位数
        {
            f = find(n);
            if(f)
                printf("%4d",n);
        }
        printf("
    ");
    }
    

    11、写一个函数,使其能求出一元二次方程的解。(参考函数原型:void s(int a,int b,intc),a、b、c 分别代表一元二次方程的系数)

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    float x1,x2;
    
    void s(int a,int b,int c)
    {
        int s;12
        s = b * b -4 * a * c;
        //求两个解
        x1 = (sqrt(s) - b) / (2 * a);
        x2 = (-sqrt(s) - b) / (2 * a);
    }
    main()
    {
        int a,b,c;
        printf("请输入一元二次方程的系数:");
        scanf("%d,%d,%d",&a,&b,&c);
        if(a == 0)//去掉 a 为 0 的不合法方程
        {
            printf("a 不能为 0!
    ");
        }
        else
        {
            s(a,b,c);
            printf("方程的解为:%f 和%f
    ",x1,x2);
        }
    }
    

    12、写一个程序,从键盘输入 5 个正整数,然后求出它们的最小公倍数,并显示输出(通过调用对两个正整数求最小公倍数的函数实现)(参考函数原型:int find(int i,int j))

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    int find(int i,int j)
    {
        int temp,a,b;
        if(i<j)//保证用较大的数除以较小的数
        {
            temp=i;
            i=j;
            j=temp;
        }
        a=i;
        b=j;
        while(b!=0)//辗转相除
        {
            temp=a%b;
            a=b;
            b=temp;
        }
        return(i*j/a);
    }
    main()
    {
        int a[5],b,i;
        printf("请输入 5 个整数:");
        for(i=0; i<5; i++)
            scanf("%d",&a[i]);
        b=find(a[0],a[1]);//调用函数对 5 个整数进行处理
        b=find(b,a[2]);
        b=find(b,a[3]);
        b=find(b,a[4]);
        printf("5 个整数的最小公倍数是%d
    ",b);
    }
    

    13、如果一个数正好是它的所有约数(除了它本身以外)的和,此数称完备数,如:6,它的约数有 1、2、3,并且 1+2+3=6。求出 30 000 以内所有的完备数,并显示输出(求完备数用函数实现)(参考函数原型:void find(int j),直接在子函数中输出完备数及其所有约数)

     算法分析:

    对于整数 j,要求出所有的约数,需要对小于 j 的所有数进行循环。在每求

    出一个约数的同时,j 减去这个约数,再将结果赋给 j,如果是完备数,最后的结果将是 0。
    需要注意是的,j 的值在不断变化,为了保证 j 一直用初值进行求约数操作,所以首先将 j
    的值赋给一个中间变量 s,利用 s 来进行减操作,让两步操作不相互影响。

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    int k[20];
    
    void find(int j)
    {
        int i,n,s;//i 为因子
        n = -1;
        s=j;
        for(i=1; i<j; i++)
        {
            if((j%i)==0)
            {
                n++;
                s = s - i;
                k[n]=i;//将每个因子赋给数组 k
            }
        }
        if(s==0)
        {
            printf("%d 是一个完备数,它的因子是:",j);
            for(i=0; i <= n; i++)
                printf("%6d",k[i]);//输出
            printf("
    ");
        }
    }
    main()
    {
        int n;
        printf("符合条件的数有:
    ");
        for(n=1; n<30000; n++)
            find(n);
    }
    

    14、如果有两个数,每一个数它的所有约数(除了它本身以外)的和正好等于对方,则称这两个数为互满数,求出 30 000 以内所有的互满数,并显示输出。求一个数它的所有约数(除了它本身以外)的和用函数实现(参考函数原型:int factor(int j))

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    int k[40];
    #define N 30000
    int factor(int j)
    {
        int i,n,s;//i 为因子
        n = -1;
        s=j;
        for(i=1; i<j; i++)
        {
            if((j%i)==0)
            {
                n++;
                s = s - i;
                k[n]=i;//将每个因子赋给数组 k
            }
        }
        s=1;
        for (i=1; i<=n; i++)s+=k[i]; // 将每个因子累加
        return s;
    }
    void main()
    {
        int s1,s2,m,n;
        for (m=2; m<N; m++)
        {
            s1=factor(m);
            for (n=m+1; n<N; n++)
            {
                s2=factor(n);
                if(s1==s2)
                    printf("%d和%d是互满数
    ",m,n);
            }
        }
    }
    

    15、函数实现将输入的一组数据逆序输出(参考函数原型:void isort(int a[]))

    算法分析:

      长度为 n 的数组 a[n]逆序的实现方法就是将 a[i]和 a[n−i−1]交换。  

    代码:

    #include <stdio.h>
    #include <stdlib.h>
    #define N 5
    
    void isort(int a[])
    {
        int i,temp;
        for(i=0; i<N/2; i++) //交换
        {
            temp=a[i];
            a[i] = a[N - i - 1];
            a[N - i - 1] = temp;
        }
    }
    main()
    {
        int a[N],i;
        printf("请输入%d 个数据:
    ",N);
        for(i=0; i<N; i++)
            scanf("%d",&a[i]);
        isort(a);
        printf("逆序输出的结果是:");
        for(i=0; i<N; i++)
            printf("%d	",a[i]);
        printf("
    ");
    }
  • 相关阅读:
    搭建自己的博客(九):使用shell模式批量添加博客文章并增加分页功能
    搭建自己的博客(八):使用fontawesome框架来添加图标以及美化详情页
    linux系列(十):cat命令
    linux系列(九):touch命令
    搭建自己的博客(七):使用bootstrap框架美化导航栏
    linux系列(八):cp命令
    搭建自己的博客(六):添加首页,使用css对界面做美化
    linux系列(七):mv命令
    Re-enable extensions not coming from Chrome Web Store on Chrome v35+ (with enhanced security)
    liblensfun 在 mingw 上编译时遇到的奇怪问题
  • 原文地址:https://www.cnblogs.com/pam-sh/p/12384776.html
Copyright © 2011-2022 走看看