切近学习者的C语言讲解合集_哔哩哔哩_bilibili 上述是我在B站发布的相应视频 目录
一,数组是什么?
数组又分为一维数组和二维数组。
无论是一维数组还是二维数组,都是一组相同数据类型的有序集合,它能将一系列相同类型的数据看作一个整体,使用一个名字命名,再用下标进行分量标识,在内存中连续存放,用数组名和下标可以唯一地确定数组元素。
分别给大家看看最基本的定义和初始化问题
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' };//当把数据全部给出时,可以省略数组长度
还要提一下的:
这是为什么?这么小的区别,为什么输出会不一样?
我把这个语句屏蔽掉也没啥用。
这就是一个基础概念的问题,在定义数组时初始化,初始化是对整个数组进行操作,而后面那种方式是对a[10]进行赋值,但是数组长度为10,最大下标为9,所以必须要加{},不然就会报错。
加了花括号我也不知道有啥用。。。。a数组中就没有第十一个元素。
那么,邪恶的事情又来了。
由上面三张图我们可以知道
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} };
//可以在里面加花括号也可以不加,都是一样的
二维数组省略长度时,只能省略行下标的书写,这是规定
二维数组是不是也有这种邪恶的事呢?
嘿嘿嘿,有的呢!
这样的话是不是会方便很多呢?嘿嘿嘿,不要说我为啥还有一些基础的东西不讲,我们都开始深究了,太基础的东西我只说重要一些的。
这也是一种比较常见的初始化二维数组的方法。
让我们接下来再看看字符串数组的初始化,因为字符串有一个专门的输入函数gets,输入一整行的字符串,所以可以只用一个for循环来完成初始化。
每次输入一行后,输入一个回车键,跳出当前的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语言中规定,只能引用单个的数组元素,而不能一次引用整个数组。
数组名加1的含义是往后走一个元素的大小,&数组名+1的含义就是往后走一个数组的长度。
4.下标从0开始,下标不能越界。因为,一旦发生下标越界,就会把数据写到其他变量所占的存储单元中,甚至写入程序代码段,有可能造成不可预料的后果。
5.虽然C语言规定,只有静态存储的数组才能初始化,但一般的C语言编译系统都允许对动态存储的数组赋初值。如果静态存储的数组没有初始化,系统将自动给所有的数组元素赋值为0;
6.使用数组时,一般使用宏定义。
宏定义有宏定义的优势,修改更方便,只需要在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,不需要继续检查
————————————————
版权声明:本文为CSDN博主「cbsheng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cbs612537/article/details/8217425
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.二维数组其实就是一种特殊的一维数组,二维数组存储方式就是类似一维数组的。
4.二维数组的数组名指的是数组的首地址,即第一行的地址。
5.数组名不能做自增自减运算,数组名是地址常量,不能做此类运算。
请大家务必要把题目弄懂弄透!
希望大家能学到东西,也静待大家斧正和指教!!!