数组
数组是一种基本的数据结构,用于存储相同类型的多个元素。数组中的每个元素可以通过索引来访问,索引从 0 开始。
数组在声明时必须指定元素的类型和数量,这些元素在内存中是连续存储的,且一旦声明,数组的大小就固定了,不能动态改变。熟悉内存架构的话可以知道数组一般存放在栈上,而一些动态分配的数组则放在堆空间中。
⚠️:定义数组的时候尽量不要出现突兀的数字
一、一维数组:
1、数组的定义:
1、定义:
【存储类型】 数据类型 标识符【下标】
#define M 3
int arr【M】;
2、初始化:
int arr【M】 = {1,2,3}(全部初始化)
也可以不进行初始化和部分初始化
⚠️:数组初始化默认是auto类型即带有不确定因素,若定义为static类型则不进行初始化数组里全为0
3、元素引用:
【数组名】+下标
4、数组名
数组名是表示地址的常量,也是数组的起始位置输出时用%p表示(printf(“arr=%p\n”,arr);)
5、数组越界
超出定义的范围,但是不会报错
2、一维数组的应用:
1、斐波那契数列前十项:
将数组中的所有元素都循环输出:
for(i=2;i<sizeof(数组名)/sizeof(数组名【0】);i++)
//其中第二项的作用是整体的大小除以第一个数的大小即为共有多少个元素,避免产生数组越界现象
{
fib[i]=fib[i-1]+fib[i-2];
}
2、冒泡排序法:
使数组中的前后两个数进行比较,再交换位置,将最大数拿出数组,其余数归为新的数组。这样的前后比较每一次比较的次数是数组中元素减一次,即n-1。
当数组中只剩下一个元素是,那么他应该是最小的,所以不需要再比较,故⚠️:总排序要n-1次
void bubbleSort(int arr[], int n) {
int i, j, tmp;
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
时间复杂度计算:
最好情况:O(n)即每个元素都排好序,只需要执行n-1次。
最坏情况:O(n^2)即逆序排放,总共需要n-1+n-2+....+1=n(n-1)/2次
3、进制转换:
对指定整数num,计算它的任意进制(base)数:
int i=0;
while (num != 0) {
n[i] = num % base;
num = num / base;
i++;
}
for (i--; i >= 0; i--) {
if (n[i] >= 10)
printf("%c", n[i] - 10 + 'A');
else
printf("%d", n[i]);
}
printf("\n");
}
例如12转化为10进制数:第一次:n[0]=2;第二次n[1]=1;所以输出12。
计算16进制用ASCII码值进行10以上数的转换
注意每次取余后结果都应该逆序读取,所以数组逆向输出。
二、二维数组:
1、数组的定义:
定义:
【存储类型】 数据类型 标识符 【行下标】 【列下标】
初始化:
int a【M】【N】
二维数组一般采用for嵌套的形式进行输入赋值
for(i=0;i<M;i++)
for(j=0;j<N;j++)
scanf(“%d”,a【M】【N】);
或者:int a【M】【N】={{1},{2}};(如果不打括号则为按空间赋值)
⚠️:初始化时可以省略行号
2、数组的应用:
1、行列倒转:
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
transposed[j][i] = original[i][j];
}
}
用新数组存放行下标和列下标互换的元素。
2、求数组中的最大值
思路:用冒泡排序的思想依次比较两个元素的大小,记录较大元素的行下标和列下标,用两个for循环嵌套。较为简单。
3、数组求和
思路:利用统计法,为数组中的每一行或每一列进行累加求和,最后将求和相加
也可以进一步统计每一行每一列的大小:
扩展数组大小,初始化一个列数+1,行数+1(多一个统计行、列)的数组
//原数组为3*2
arr[3][2]={...};
a[4][3]={};
a=arr;
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
a[4][3] += a[i][j];
a[4][j] += a[i][j];
a[i][3] += a[i][j];
}
}//a[4][3]即为总和,a[4][0]-a[4][2]是列和,a[0][3]-a[4][3]是行和
三、理解数组
1、一维数组和二维数组的联系:
数组名+x,对于一维数组是下一个;对于二维数组则是下一行
因为对于二维数组而言,它可以看做是被分为多个行数组组成的一维数组:即a【2】【3】-> a【0】(a【0】【1】、a【0】【2】...)、a【1】(a【1】【1】、...)
所以+1即是跳转到下一行
2、多维数组:
三维数组:在二维数组的基础上再细分为多个一维数组:
int a 【2】【2】【3】:
a【0】【0】->a【0】【0】【1】、a【0】【0】【2】.....
总结:无论是二维还是三维数组,都需要与指针的使用相结合。不同维度的数组名代表的意义不同
3、字符数组:
定义:
【储存类型】 数据类型 标识符 【下标】
初始化:
char a【M】={‘q’,‘w’,‘e’};或者char a【M】 = "qwe";
⚠️:注意定义的大小要合适,因为字符串的存储方式还有一个尾0,可以用/0表示
输入输出:
scanf和printf:
scanf中%s不能识别例如空格的分隔符
常用函数:
在<string.h>中有以下功能强大的字符函数组:
strlen:字符串长度但是不包含尾0大小,且为int类型
sizeof:在内存中真正占用的空间,包含尾0,int
strcpy:strcpy(目标数组,字符串)
strncpy:(目标数组,字符串,大小)防止越界现象
strcat:(目标数组,字 符串)连接字符串来覆盖尾0
strncat:防止越界
strcmp:(字符串1,字符串2)比较两个字符串的ASCII,并返回整型差值
strncmp:比较前n个字符
字符数组的应用:
单词计数:
这是一个与文件IO操作相关的查询文本中某个单词出现的次数的程序:
#include <stdlib.h> #include <string.h> #define SIZE 1024 int find_words(char const*word,FILE*fp){ char buffer[SIZE]; int count=0; char *found; while (fgets(buffer,SIZE-1,fp)!=NULL){ char *temp=buffer; while ((found=strstr(temp,word))!=NULL){ count++; // 发现关键字,计数增加 temp=found+ strlen(word); } } return count; } int main(int argc,char **argv) { FILE *fp; int count; char const*word; if(argc<3){ fprintf(stderr,"Usage:%s <dest_filename> <string>\n",argv[0]); } fp=fopen(argv[1],"r"); if(fp==NULL){ perror("fopen():\n"); exit(1); } word=argv[2]; count=find_words(word,fp); printf("%s has appeared for %d times.\n",word,count); fclose(fp); return 0; }
可以先尝试理解该程序。