深究C语言-1.数组篇

简介: 无论是一维数组还是二维数组,都是一组相同数据类型的有序集合,它能将一系列相同类型的数据看作一个整体,使用一个名字命名,再用下标进行分量标识,在内存中连续存放,用数组名和下标可以唯一地确定数组元素。

学习C语言3-深究数组(上)


一,数组是什么?


数组又分为一维数组和二维数组。


无论是一维数组还是二维数组,都是一组相同数据类型的有序集合,它能将一系列相同类型的数据看作一个整体,使用一个名字命名,再用下标进行分量标识,在内存中连续存放,用数组名和下标可以唯一地确定数组元素。


分别给大家看看最基本的定义和初始化问题


1.一维数组


数据类型 数组名[数组长度];
char str[100];
char str[100] = { 1,2,3 };
char str[100] = { 'a','b','c' };
char str[100] = "abc";
char str[]= { 'a','b','c' };//当把数据全部给出时,可以省略数组长度


还要提一下的:


d9bbbb8601954500a0348c42375d45f0.png


5059f2990f09435194107ef44e5a48bc.png


这是为什么?这么小的区别,为什么输出会不一样?


90bfefc3413a450095c36f3ee2dbc926.png


我把这个语句屏蔽掉也没啥用。


这就是一个基础概念的问题,在定义数组时初始化,初始化是对整个数组进行操作,而后面那种方式是对a[10]进行赋值,但是数组长度为10,最大下标为9,所以必须要加{},不然就会报错。


加了花括号我也不知道有啥用。。。。a数组中就没有第十一个元素。


那么,邪恶的事情又来了。


34968366ce0042609f14e5e51567c557.png


由上面三张图我们可以知道


1)数组未初始化,数组里面的值都是随机值。

2)数组初始化为{0},数组里面的值都是0。

3)数组初始化为{非零值},数组里面第一个值是非零值,其他的值都是0。


2.二维数组


数据类型 数组名[行下标][列下标];


数据类型 数组名[行下标][列下标];
char a[100][100];
char a[3][4] = { 1,2,3,4,5,6,7,8,9,0,11,12 };
char a[3][4] = { {1,2,3,4},{5,6,7,8},{9,0,11,12} };
//可以在里面加花括号也可以不加,都是一样的
二维数组省略长度时,只能省略行下标的书写,这是规定


二维数组是不是也有这种邪恶的事呢?


嘿嘿嘿,有的呢!


4e147dd3d8104591a7e0fe6dbbc29122.png


c98cd6bc187d47ff857af6f317b87d93.png


74554e92aee9414c994e6e763fd77b8f.png


这样的话是不是会方便很多呢?嘿嘿嘿,不要说我为啥还有一些基础的东西不讲,我们都开始深究了,太基础的东西我只说重要一些的。


1295611083e04c5a827d20a57a31b5f4.png


这也是一种比较常见的初始化二维数组的方法。


让我们接下来再看看字符串数组的初始化,因为字符串有一个专门的输入函数gets,输入一整行的字符串,所以可以只用一个for循环来完成初始化。


d8f86ddb6127411a8bb914f77114020e.png



76a208f787124bd6882c0bef5dc5eff3.png


e8a9f961460c4d28a2fc6ff1246a34ac.png


每次输入一行后,输入一个回车键,跳出当前的for循环,进行下一次,可以少写,不能多写,多的部分会被舍弃。


现在来讲一些其他细节的东西


1.printf,scanf与puts,gets


scanf遇到空格或回车就结束


gets遇到回车才结束。


scanf("%d",&arr);//一般scanf后面都是要加&符号的,如果是写到数组里面,加不加&都无所谓。
sacnf("%s",str);
gets(str)//直接用数组名即可


2.“a”与‘a’的区别


“a”占两个字节,因为”“是字符串标志,系统会自动给字符串的结尾加上一个结束标识符'\0',所以这个占了两个字节


‘a’只占一个字节,因为‘’是字符标志,只有a一个字符,只占一个字节。


3.数组名是一个地址常量,存放数组内存空间的首地址,如果是&数组名,取出的就是整个数组的地址,当然,这两个的值是没有什么区别的,但是在一定的情况下就会出现区别。C语言中规定,只能引用单个的数组元素,而不能一次引用整个数组。


094eb2f3db684eb3b3862b216e921267.png


f049793a33564d82bdca970fb737ba50.png


数组名加1的含义是往后走一个元素的大小,&数组名+1的含义就是往后走一个数组的长度。


4.下标从0开始,下标不能越界。因为,一旦发生下标越界,就会把数据写到其他变量所占的存储单元中,甚至写入程序代码段,有可能造成不可预料的后果。


5.虽然C语言规定,只有静态存储的数组才能初始化,但一般的C语言编译系统都允许对动态存储的数组赋初值。如果静态存储的数组没有初始化,系统将自动给所有的数组元素赋值为0;


575a75c79518440190e5b33fcfa0b0cf.png


6.使用数组时,一般使用宏定义。


6061ada6e251483f8bfeeabb16bd3a66.png


宏定义有宏定义的优势,修改更方便,只需要在define后面修改就好;


7.C语言支持多维数组,最常见的多维数组是二维数组。


二,话不多说,咱来上题。


一,基础一二维数组问题


//输出大于平均值的数
#include<stdio.h>
int main(){
  int i,n;
  double ave,sum;
  int a[10];
  printf("请输入n:");
  scanf("%d",&n);
  if(n>=1&&n<=10){
    printf("请输入%d个数据:",n);
    for(i=0;i<n;i++){
      scanf("%d",&a[i]);//需要一个循环语句来输入数组的数据 
    }
    sum=0;
    for(i=0;i<n;i++){
      sum+=a[i];//同样也需要一个循环语句来累加 
    }
     ave=sum/n;
     printf("ave=%.2f\n",ave);
     printf(">ave");
     for(i=0;i<n;i++){//数组中的for循环不能用等于号哦,用等于号就需要多输出一个数据,因为数组从零开始 
      if(a[i]>ave)
      printf("%d ",a[i]);
     }
     printf("\n");
  }
    else
      printf("Invlid Value.\n");
  return 0; 
} 


#include<stdio.h>
#define MAXN 46//定义在最上面,需要更改时便只需改这一个地方。 数组都可以如此,更方便 
int main(){
  int i,n;
  int fib[MAXN]={1,1};//先输出前两项 
  printf("请输入n:");
  scanf("%d",&n);
  if(n>=1&&n<=46){
    for(i=2;i<n;i++){//i=2,是因为,数组从零开始,i=2时,其实是第三项 
      fib[i]=fib[i-1]+fib[i-2];//前一项等于后两项之和 
    }
    for(i=0;i<n;i++){
      printf("%6d",fib[i]);
    if((i+1)%5==0)
      printf("\n");
    }
      if(n%5!=0)
        printf("\n");
  }
  else
    printf("Invalid Value!\n");
  return 0;
} 


#include<stdio.h>
#define MAXN 8
int main(){
  int i,n,response;
  int count[MAXN+1];//实际问题是以1开头的,所以定义一个更长的,其实也可以在宏定义时定义更长的 
  printf("请输入n:");
  scanf("%d",&n);
  for(i=1;i<=MAXN;i++)
  count[i]=0;//数据的初始化,避免该存储单元之前的数据影响 !!!!!!! 
  for(i=1;i<=n;i++){
    printf("Enter your response:");
    scanf("%d",&response);
    if(response>=1&&response<=MAXN)
    count[response]++;//等价于count[response]+=1. 上面已经初始化过了,所以出现一次就会累加一次 
    else
      printf("Invalid:%d\n",response);
  }
  printf("result:\n");
  for(i=1;i<=MAXN;i++){
    if(count[i]!=0)
    printf("%4d%4d\n",i,count[i]);
  }
  return 0;
} 


这个题要看看!!!


#include<stdio.h>
#define MAXN 6
#define MAXM 6
int main(){
  int col,i,j,m,n,row;
  int a[MAXM][MAXN];
    printf("请输入m,n:");
    scanf("%d%d",&m,&n);
    printf("请输入%d个数:\n",m*n);
  for(i=0;i<m;i++){
    for(j=0;j<n;j++){
      scanf("%d",&a[i][j]);
    }
  }//二维数组的初始化方式,双重for循环 
  row=col=0;
  for(i=0;i<m;i++){//遍历数组找出最大值 
    for(j=0;j<n;j++){
      if(a[i][j]>a[row][col]){
        row=i;
        col=j;
      }
    }
  }
  printf("max=a[%d][%d]=%d\n",row,col,a[row][col]);
  return 0;
} 


把上面这几个东西搞熟,基本的一二维数组问题就都可以解决。


二,数组的深入用法


数组的作用当然不止这些,数组的优越性在于元素众多,及它的可选择性,因为元素众多,所以你可以选择多种元素。这个在后面尤为重要,(所以咱后面再讲,嘿嘿嘿)。


我们这里主要来讲一讲其他的两个主要作用,排序与查找。


上题目:


1.顺序查找法


#include<stdio.h>
#define MAXN 10
int main(){
  int i,flag,n,x;
  int a[MAXN];
  printf("please input n,x:");
  scanf("%d%d",&n,&x);
  printf("请输入%d个数:",n);
  for(i=0;i<n;i++){
    scanf("%d",&a[i]);//向数组内添加数据 
  }
  flag=0;
  for(i=0;i<n;i++){
    if(a[i]==x){
      printf("Index is %d\n",i);
      flag=1;
    }
  }
  if(flag==0)
  printf("Not found!\n");
  return 0;
} 


2.


#include<stdio.h>
#define MAXN 10
int main(){
  int i,index,n;
  int a[MAXN];
  printf("Enten n:");
  scanf("%d",&n);
  printf("请输入%d个数:",n);
  for(i=0;i<n;i++)
    scanf("%d",&a[i]);//数组输入数据,借助一个循环。 
  index=0;//假设index(首地址)为最小的项的下标 
  for(i=0;i<n;i++){
    if(a[i]<a[index])
    index=i;//如果有比他更小的,就换到首地址去 
  }
  printf("min is %d\tsub is %d\n",a[index],index);
  return 0;
} 


3.a与b中找相同(重点看题4)


#include<stdio.h>
int main(){
  int a[]={1,2,3,4,5},b[]={3,4,5,6,7,8},c[6];
  int i,j,k=0;
  for(i=0;i<5;i++){ 
      for(j=0;j<6;j++){
        if(a[i]==b[j]){
      c[k]=a[i];
      k++;
      break;
    }
  }
}
  for(i=0;i<k;i++){
    printf("%d ",c[i]);
  }
  return 0;
} 


4.a与b中找不同


#include<stdio.h>
#define N 10
int main(){
  int m,n,i,j,k,a[N],b[N],c[2*N],flag=0;
  printf("请输入一个数:");
  scanf("%d",&m);
  printf("请输入%d个数据:",m);
  for(i=0;i<m;i++){
    scanf("%d",&a[i]);//初始化a数组 
  }
    printf("请输入一个数:");
  scanf("%d",&n);
  printf("请输入%d个数据:",n);
  for(i=0;i<n;i++){
    scanf("%d",&b[i]);//初始化b数组 
  }
  for(i=0;i<m;i++){
    for(j=0;j<n;j++){
      if(a[i]==b[j])
      break;//将a数组中的元素拿出与b数组中的元素比较 
    }
    if(j>=n){
    flag=1;
    c[k++]=a[i];//如果是正常循环结束,则表明a中的元素无与b中相同的元素 ,且flag=1 
  }
  } 
  for(j=0;j<n;j++){
    for(i=0;i<m;i++){
      if(b[j]==a[i])
      break;
    }
    if(i>=m){
    flag=1;
    c[k++]=b[j];//b也要与a比较 
    }
  }
  for(i=0;i<k;i++)
  printf("%d ",c[i]);
  if(flag==0)
  printf("No found!");//避免两数组无非公有元素而无操作 
  return 0;
}


5.最大最小值交换位置


#include<stdio.h>
#define N 10
int main(){
  int n,i,t,a[N],max,min;
  printf("请输入一个数:");
  scanf("%d",&n);
  printf("请输入%d个数:",n);
  for(i=0;i<n;i++)
  scanf("%d",&a[i]);
  max=0;
  min=0;//初始化最大最小值,使第一项为最大最小值。 
  for(i=0;i<n;i++){
    if(a[max]<a[i])
    max=i;
    if(a[min]>a[i])
    min=i;
  }
  t=a[max];
  a[max]=a[n-1];
  a[n-1]=t;
  //赋值过程一定要放在for循环外,循环结束了以后才能知道最大最小,切记切记 
  t=a[min];
  a[min]=a[0];
  a[0]=t;
  printf("%d   %d",a[0],a[n-1]);
  return 0;
}


6.选择法排序


#include<stdio.h>
#define MAXN 10
int main(){
  int i,index,k,n,temp;
  int a[MAXN];
    printf("请输入n:");
      scanf("%d",&n);
    printf("请输入%d个数:",n);
  for(i=0;i<n;i++)
    scanf("%d",&a[i]);
  for(k=0;k<n-1;k++){
    index=k;
    for(i=k+1;i<n;i++){
      if(a[i]<a[index])
      index=i;
    }
    temp=a[index];
    a[index]=a[k];
    a[k]=temp;
  }//k最大也只是n-2,i最大为n-1,即将a[k]与a[i]比较,在for循环结束后,下标已经交换完成,再交换数据 
  printf("排序为:"); 
  for(i=0;i<n;i++)
    printf("%d ",a[i]);
  printf("\n");
  return 0;
} 
//第1轮在待排序记录r[1]-r[n]中选出最小的记录,将它与r[1]交换;第2轮在待排序记录r[2]-r[n]中选出最小的记录,将它与r[2]交换;以此类推,第i趟在待排序记录r[i]~r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。


7.二分查找法


#include<stdio.h>
int main(){
  int low,high,mid,n=10,x;
  int a[10]={1,2,3,4,5,6,7,8,9,10};
  printf("请输入x:");
  scanf("%d",&x);
  low=0;
  high=n-1;
  while(low<=high){
    mid=(high+low)/2;
    if(x==a[mid])
    break;
    else if(x<a[mid])
    high=mid-1;
    else
    low=mid+1;
  }//这个循环就是二分查找法的主体部分。 
  if(low<=high)
  printf("Index is %d\n",mid);
  else
  printf("Noy Found");
  return 0;
} 


8.冒泡排序


#include<stdio.h>
#define MAXN 10
void swap(int *px,int *py);
void bubble(int a[],int n);
int main(){
  int n,a[MAXN],i;  
  printf("Enter n(n<=10):");
  scanf("%d",&n);
  printf("Enter %d integers:",n);
  for(i=0;i<n;i++)
  scanf("&d",&a[i]);
  bubble(a,n);//用数组名即可。 
  printf("After sorted:");
  for(i=0;i<n;i++)
  printf("%3d",a[i]);
  return 0;
}
void bubble(int a[],int n){
  int i,j,t;
  for(i=1;i<n;i++){
    for(j=0;j<n-i;j++){
      if(a[j]>a[j+1])
      swap(&a[j],&a[j+1]);
    }
  }
}
void swap(int *px,int *py){
  int t;
  t=*px;
  *px=*py;
  *py=t;
}


***9.判断回文-数组-递归-指针三种方法


1)数组


#include<stdio.h>
#define MAXLINE 80
int main(){
  int i,k;
  char line[MAXLINE];
  //输入字符串
  printf("Enter a string:"); 
  //输入字符串 
  k=0;
  while((line[k]=getchar())!='\n')
  k++;
  line[k]='\0';//必须要人为加上‘\0’. 
  //分别指向第一个和最后一个元素位置。 
  i=0;
  k-=1;
  while(i<k){
    if(line[i]!=line[k])//若对应字符不相等,则提前结束循环。 
      break;
    i++;
    k--;
  }
  //判断while循环是否正常结束,若是则说明字符串是回文。 
  if(i>=k)
    printf("是回文!");
  else
    printf("不是回文!");
  return 0;
}


2)递归


//递归 
#include<stdio.h>
#include<string.h>
int judge(int low,int high,char *arr,int len){
  //最终条件。
  if(len==0 || len==1) 
    return 1;
  if(arr[low]!=arr[high])
    return 0;
  return judge(low+1,high-1,arr,len-2);
}
int main(){
  char arr[10]="aaabbaaa";
  int len=strlen(arr);
  if(judge(0,len-1,arr,len))
  printf("是!");
  else
  printf("不是!"); 
  return 0;
} 
/*递归的作用在于把问题的规模不断缩少,直到问题缩少到简单地解决 
通过观察可以知道,一个回文字符串其中内部也是回文。所以,我们只需要以去掉两端的字符的形式一层层检查,
每一次的检查都去掉了两个字符,这样就达到了缩少问题规模的目的。
1. 字符串长度可能会奇数或偶数:
如果字符串长度是奇数,字符串会剩下最中间那位字符,但其不影响回文。当检查到长度为1的时候即代表此字符串是回文
如果字符串长度是偶数,当两端的字符串两两比较检查后不会剩下字符。即检查到长度为0的时候即代表此字符串是回文
2. 如果检查到两端两个字符不相同。则说明此字符串不是回文,直接返回0,不需要继续检查


3)指针与数组方法差不多。自己理解吧。


10.方阵转置


#include<stdio.h>
#define MAXN 6
int main(){
  int i,j,n,temp;
  int a[MAXN][MAXN];
  printf("ENTER n:");
  scanf("%d",&n);
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      a[i][j]=i*n+j+1;//给数组元素赋值 
    }
  }
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      if(i<=j){
        temp=a[i][j];
        a[i][j]=a[j][i];
        a[j][i]=temp;
      }
    }
  }
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      printf("%4d",a[i][j]);
    }
    printf("\n");
  }
  return 0;
} 


三,小细节


1.二维数组的每一行都可看做一个一维数组,可直接用数组名+[行号]代表该行首元素地址。


2.数组要重视长度,防止越界。


3.二维数组其实就是一种特殊的一维数组,二维数组存储方式就是类似一维数组的。


f054443415034d9f848052c15aa55be7.png


4.二维数组的数组名指的是数组的首地址,即第一行的地址。


5.数组名不能做自增自减运算,数组名是地址常量,不能做此类运算。


请大家务必要把题目弄懂弄透!


希望大家能学到东西,也静待大家斧正和指教!!!

目录
相关文章
|
2天前
|
存储 编译器 数据库
结构体数组在C语言中的应用与优化技巧
结构体数组在C语言中的应用与优化技巧
|
9天前
|
存储 编译器 C语言
C语言数组详解
C语言数组详解
13 1
|
11天前
|
存储 算法 C语言
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
|
10天前
|
C语言
C语言刷题(数组)
C语言刷题(数组)
|
10天前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
11天前
|
C语言
【C语言刷题每日一题】一维数组的交换
【C语言刷题每日一题】一维数组的交换
|
11天前
|
存储 C语言
【C语言刷题系列】求一个数组中两个元素a和b的和最接近整数m
【C语言刷题系列】求一个数组中两个元素a和b的和最接近整数m
|
12天前
|
C语言
【C语言】:详解函数指针变量,函数指针数组及转移表
【C语言】:详解函数指针变量,函数指针数组及转移表
14 2
|
12天前
|
C语言
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
【C语言】:详解指针数组,数组指针及(二维)数组传参(2)
10 1
|
12天前
|
Serverless C语言
【C语言】:对(一维)数组与指针的深入理解(1)
【C语言】:对(一维)数组与指针的深入理解(1)
10 1