之前,在零基础C语言——数组-CSDN博客中,我们简单学习了一维数组的知识。
多维数组
多维数组的声明一般形式如下:
type name[size1][size2]……[sizeN];
二维数组
是多维数组中最简单的形式。在本质上,是一个一维数组的列表,声明一个x行y列的二维整型数组。
type arrayName[x][y];
一个二维数组可以被认为是一个带有x行y列的表格或矩阵。用矩阵形式表示一个二维数组,是逻辑上的概念,能形象化的表示出行列关系。在内存中,各元素是连续存放的,不是二维,是线性的。
引用数组元素
表示形式:
数组名[下标][下标]
如一维数组的一样,二维数组中,第一个下标表示行下标(行索引),第二个为列下标(列索引)。(行序号和列序号都是从0起算)
初始化
1.分行赋值——直观的表示
int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
2.将所有数据写在一个括号内,按数组元素在内存中的排序顺序对各元素赋初值。
int arr[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
3.对部分元素赋初值。
int arr[3][4]={{1},{5},{9}};
//运行结果是
//1 0 0 0
//5 0 0 0
//9 0 0 0
它的作用是只对各行第一列的元素赋值,其余元素自动为0。
也可以对各行中的某一个元素赋初值。
int arr[3][4]={{1},{0,6},{0,0,11}};
//运行结果是
//1 0 0 0
//0 6 0 0
//0 0 11 0
当然,可以对特定元素赋值,自此不演示。
也可以某一行元素不赋值。
int arr[3][4]={{1},{},{9}};
4.如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对对第一维的长度可以不指定,但第二维的长度不能省。系统会根据数据总个数和第二维的长度算出第一位的长度。
字符数组
字符型数据是以字符的ASCII代码C储单元中的,一般占一个字节。由于ASCII代码属于整数形式,在C99中,把字符类型归纳为整型类型中的一种。
C语言中没有字符串类型,也没有字符串变量,字符串是存放在字符型数组中的。
定义字符数组
由于字符类型的存储方式,因此用整型数组来存放字符数据。
初始化
char c[10]={'I',' ','a','m'};
将字符用 ‘ ’ 引起,其余元素自动定为空字符 ‘ \0 ’。
引用与一维数组的一样
字符串和字符串的结束标志
在实际工作中,更关注的是字符串的有效长度,而非字符数组长度。
C语言规定了一个“字符串结束标志”。以字符’\0‘作为结束标志。遇到字符’\0'时,表示字符串结束。
C系统在用字符数组存储字符串常量时会自动增加一个'\0'作为结束符。例如“C program"共有9个字符,放到一维数组中占据10个字节。
’\0'代表ASCII代码为0的字符,ASCII码为0的字符不是一个可以显示的字符,而是一个”空操作符“,即什么也不做。
在执行printf函数时,每输出一个字符检查一次,遇到‘\0'时停止输出。
在此基础上,我们可以用一种新的方法,用字符串常量来使字符数组初始化。
char c[]={"I am happy"};
//也可省略括号
char c[]="I am happy";
说明:字符数组并不要求它的最后 一个字符为'\0',人为加上是为了便于观察。
字符串的输入与输出
(1)逐个字符输入输出,使用格式符”%c“。 (2)将整个字符串一次输入输出,用格式符"%s"(对应单词string字符串)。
如果一个字符数组中包含一个以上的'/0',则遇第一个'\0'时输出就结束。
使用scanf函数时:1)当输入一个字符串时,输入项是已定义的字符数组名char c[6]; 2)当输入多个字符串,应在输入时以空格分隔。由于有空格字符分隔,分成几份就用几个字符串数组。例:scanf("%s%s%s",str1,str2,str3);如果只是设置了一个数组canf("%s",str);,只会将第一个分隔的内容存入,其余不会存入。
使用字符串处理函数(STRing+……)
1.puts函数——输出一个以'\0‘结束的字符串到终端。(可用printf函数代替)
2.gets函数——从终端输入一个字符串到字符数组,并得到一个函数值(该字符数组的起始地址)。puts和gets只能输出或输入一个字符串。
3.stract函数——将后者字符数组连接到前者字符数组后面,并放在前者数组中,函数返回值为前者数组的地址。格式为:strcat(字符数组1,字符数组2);连接时将前一数组的'\0'删去,只在新数组后保留‘\0'。
4.strcpy和strncpy函数——将字符串2复制到字符数组1中。 形式:strcpy(字符数组1,字符数组2); strncpy( 字符数组1,字符数组2,n);——将字符串2前n个字符复制到字符数组1中去。
5.strcmp函数——比较字符串1和字符串2,形式:strcmp(字符串1,字符串2);
字符串比较的规则:将两个字符串自左向右逐个字符相比(按照ASCII码值比大小),直到出现不同的字符或遇到'\0'为止。如果参与比较的两个字符串都由英文字母组成,有一个简单的规律:在英文字典中位置在后的为“大”。小写字母比大写字母“大”。返回值:相同=0,1>2为正整数,1<2为负整数。
if(str1>str2) //错误
//数组名表示地址,只能用
if(strcmp(str1,str2)>0)
6.strlen函数——测试字符串长度的函数。返回值为字符串的实际长度(不包含'\0'在内)。
7.strlwr函数——将字符串中大写字母换成小写字母。形式:strlwr(字符串);
8.strupr函数——将字符串中小写字母换成大写字母。形式:strupr(字符串);
这些函数的头文件为string,即:#include<string.h>
P165
1.用筛选法求100之内的素数。
注:筛选法:即“埃拉托色尼筛选法”:埃拉托斯特尼筛法_百度百科 (baidu.com)
#include<stdio.h>
#include<math.h>
int main()
{
int i, j, n, a[101];
for (i = 1; i <= 100; i++)
{
a[i] = i; //把100个数写进数组,不使用a[0];
}
a[1] = 0; //除去1
for (i = 2; i < sqrt(100); i++)
{
for (j = i + 1; j <= 100; j++)
{
if (a[i] != 0 && a[j] != 0)
{
if (a[j] % a[i] == 0)
{
a[j] = 0; //挖去非素数
}
}
}
}
for (i = 2, n = 0; i <= 100; i++)
{
if (a[i] != 0) //筛选素数
{
printf("%d\t", a[i]); //输出
n++;
}
if (n == 10) //换行,制表
{
printf("\n");
n = 0;
}
}
printf("\n");
return 0;
}
2.用选择法对10个整数排序。
int main()
{
int i, j, mid, com, arr[10];
for (i = 0; i <10; i++)
{
printf("请输入第%d个数:", i+1);
scanf("%d", &arr[i]);
}
printf("\n");
for (i = 0; i <9; i++)
{
com = i; //
for (j = i + 1; j < 10; j++)
{
if (arr[com] > arr[j]) //判断
{
com = j;
}
}
mid = arr[i]; /交换
arr[i] = arr[com];
arr[com] = mid;
}
printf("排序为:");
for (i = 0; i < 10; i++)
{
printf("%d ",arr[i]);
}
return 0;
}
3.求一个33的整型矩阵对角线元素之和。
int main()
{
int a[3][3],sum=0;
int i, j ;
printf("输入3x3矩阵计算对角线和:\n");
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
scanf("%d", &a[i][j]);
}
}
for (i = 0; i < 3; i++)
{
sum += a[i][i];
}
printf("sum=%d",sum);
return 0;
}
结果为
4.有一个已经排的数组,要求输入一个数后,按原来排序的规律将它插入数列中。
假设此数列为升序排序,
int main()
{
int a[11] = { 1,2,3,4,5,6,7,8,9,10 };
int i, j, num;
int tamp1, tamp2;
printf("原先的序列为:");
for (i = 0; i < 10; i++)
{
printf("%d ",a[i]);
}
printf("\n");
printf("请插入一个数:");
scanf("%d", &num);
if (num > a[9])
{
a[10] = num;
}
else
for (i = 0; i < 10; i++)
{
if (a[i] > num)
{
tamp1 = a[i];
a[i] = num;
for (j = i + 1; j < 11; j++)
{
tamp2 = a[j];
a[j] = tamp1;
tamp1 = tamp2;
}
break;
}
}
printf("新的排序为:");
for (i = 0; i < 11; i++)
{
printf("%d ", a[i]);
}
return 0;
}
结果为:
扩展代码的功能性可添加:输入已排好的数据,并检测其排序方式(设置函数判断是否符合规律,返回值利用switch语句判断其规律),利用函数的调用使已插入数的新数列再执行一边(或从某一边进行插入)。
5.将一个数组中的值按逆顺序重新存放。例如:原来顺序是:8,6,5,4,1.要求改为1,4,5,6,8。
注:题目要求是“存放”,不要写成逆序打印了。
int main()
{
int t, i, n;
printf("将重新排序的数的个数为:");
scanf("%d", &n);
int a[100]; //设置一个足够用的大小
printf("请输入:");
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for (i = 0; i < n / 2; i++)//交换
{
t = a[i];
a[i] = a[n - i - 1];
a[n - i - 1] = t;
}
for (i = 0; i < n; i++)
{
printf("%5d", a[i]);
}
return 0;
}
结果为:
6.输出以下的杨辉三角形(要去要输出10行)
1
1 1
1 2 1
1 3 3 1
…………
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num[10][10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j <= i; j++)
{
if (j == 0 || j == i)
{
num[i][j] = 1;//每行数字左右对称,由1开始
}
else
{
num[i][j] = num[i - 1][j] + num[i - 1][j - 1];//每个数等于它上方两数之和
}
printf("%4d", num[i][j]);
}
printf("\n");
}
return 0;
}
输出结果为:
7.输出“魔方阵”。所谓魔方阵是指这样的方阵,它的每一行,每一列和对角线之和均相等。例如,三阶魔方阵: 8 1 6
3 5 7
4 9 2
要求输出的自然数构成的魔方阵。魔方矩阵_百度百科 (baidu.com)c
void Exchange(int** pj, int tr, int tc, int n) {
n++;
if (1 <= tr && tr <= n / 2 && 1 <= tc && tc <= n) {
pj[tr][tc] += pj[n - tr][n - tc];
pj[n - tr][n - tc] = pj[tr][tc] - pj[n - tr][n - tc];
pj[tr][tc] -= pj[n - tr][n - tc];
}
}
int main() {
int n, i = 0, j = 0, ** pj;
int tr, tc;
printf("输入魔方矩阵的阶层:");
scanf("%d", &n);
// 初始化二维数组
pj = (int**)malloc(sizeof(int**) * (n + 1));
for (i = 0; i < (n + 1); i++)
pj[i] = (int*)malloc(sizeof(int*) * (n + 1));
// n为奇数时
if (n % 2 == 1) {
// 1.将1放至第一行中间
i = 1; j = n / 2 + 1;
pj[1][n / 2 + 1] = 1;
// 2.沿右上45°,依次放置剩下的数
for (int k = 2; k <= n * n; k++) {
// 行数上移,列数右移,即右上45°移动
tr = i - 1; tc = j + 1;
// 条件一:若超出,则回绕
if (tr < 1) tr = n;
if (tc > n) tc = 1;
// 条件二:若有数据,则放在上一个数字之下
if (0 < pj[tr][tc] && pj[tr][tc] <= n * n) {
tr = i + 1; tc = j;
if (tr < 0) tr = n;
}
pj[tr][tc] = k;
i = tr; j = tc;
}
}
// n为4的倍数时
else if (n % 4 == 0) {
i = 1; j = 1;
// 1.先将数据从上到下,从左到右填入
for (int k = 1; k <= n * n; k++) {
pj[i][j++] = k;
if (j > n) { j = 1; i++; }
}
// 2.将方阵的所有4*4子方阵中的两对角线上的数
// 关于大方阵中心作中心对称交换
i = 1; j = 1;
for (size_t r = 0; r < n / 4 + 1; r++) {
for (size_t c = 0; c < n / 4 + !(r % 2); c++) {
tr = 2 * r + i;
tc = 4 * c + r % 2 * 2 + j;
Exchange(pj, tr, tc, n);
Exchange(pj, tr - 1, tc, n);
Exchange(pj, tr, tc - 1, n);
Exchange(pj, tr - 1, tc - 1, n);
}
}
}
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++)
printf("\t%d", pj[i][j]);
printf("\n");
}
}
此代码无法生成6阶魔方阵。
8.找出一个二维数组中的鞍点,即该位置上的元素在该行上最大、在该列上最小,也可能没有鞍点。
注:我的想法为:每行最大的数所在的列中是否为最小。
#define N 5
#define M 4
int Saddle_point(int p, int q,int arr[M][N])
{
int Max, Min;
int i, j, m, n, k;
int count = 0;
for (i = 0; i < p; i++)
{
for (j = 0; j < q; j++)
{
printf("%d\t", arr[i][j]);//打印
if (j == (q - 1))
{
printf("\n");
}
}
}
for (i = 0; i < p;) //分行筛选
{
Max = 0, Min = 0;
n = 0, m = 0; //再次初始化
for (j = 0; j < q; j++)
{
if (Max < arr[i][j]) //找出此行最大值
{
Max = arr[i][j];
m = j; //确定最大值所在的列
n = i;
}
Min = arr[n][m];
if (j == (q - 1))
{
for (k = 0; k < p; k++)
{
if (Min > arr[k][m])//找出m列的最小值
{
Min = arr[k][m];
n = k;
}
}
}
}
if (Max != Min)//判断是否为鞍点,并返回值
{
printf("在%d行无鞍点\n", i + 1);
i++;
}
else
{
count++;
printf("在%d列的鞍点为arr[%d][%d]=%d\n", i + 1, n, m, Max);
i++;
}
}
return count;
}
int main()
{
int arr[M][N];
int i, j;
printf("请输入:\n");
for (i = 0; i < M; i++)
{
for (j = 0; j < M; j++)
{
scanf("%d", &arr[i][j]);
}
}
int count=0;
int p = sizeof(arr) / sizeof(arr[0]); //计算二维数组的列数
int q = sizeof(arr[0]) / sizeof(arr[0][0]); //计算二维数组的行数
Saddle_point( p, q,arr); //函数的调用
printf("此数组有%d个鞍点\n", count);
return 0;
}
9.有15个数按照由小到大顺序存放在一个数组中,输入一个数,要求用折半查找法找出该数是数组中第几个元素的值。如果该数不在数组中,则输出“无此数”。
#include <stdio.h>
int main()
{
int a[15];
int i,j,n,mid,flag = 0;
printf("请输入15个数:\n");
for(i = 0;i < 15;i++)
{
scanf("%d",&a[i]);
}
printf("\n请输入一个数:");
scanf("%d",&n);
i = 0;
j = 14;
while(i < j)
{
mid = (i + j) / 2;
if(a[mid] > n)
{
i = mid + 1;
}
if(a[mid] < n)
{
j = mid - 1;
}
if(a[mid] == n)
{
printf("该数是第%d个元素",mid+1);
flag = 1;
break;
}
}
if(flag == 0)
printf("无此数!");
}
10.有一篇文章,共有3行文字,每行有80个字符。要求分别统计出其中英文大写字母、小写字母、数字、空格以及其他字符的个数。
#include<stdio.h>
int main()
{
int i, j, q = 0, p = 0, z = 0, o = 0, n = 0;
char a[3][80];
for (i = 0; i < 3; i++)
{
printf("第%d行:", i + 1);
gets_s(a[i]); //字符串输入
}
for (i = 0; i < 3; i++) {
for (j = 0; a[i][j] != '\0'; j++)
{
if (a[i][j] >= 'A' && a[i][j] <= 'Z')
{
q++;
}
else if (a[i][j] >= 'a' && a[i][j] <= 'z')
{
p++;
}
else if (a[i][j] >= '0' && a[i][j] <= '9')
{
z++;
}
else if (a[i][j] == ' ')
{
o++;
}
else
{
n++;
}
}
}
printf("大写字母:%d\n小写字母:%d\n数字:%d\n空格:%d\n其它:%d\n", q, p, z, o, n);
return 0;
}
11.输出以下图形:
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
int main()
{
char a[5] = { '*','*','*','*','*' };
int i, j,k;
char space = ' ';
for (i = 0; i < 5; i++)
{
printf("\n");
printf(" ");
for (j = 1; j <=i; j++)
{
printf("%c",space);
}
for (k = 0; k < 5; k++)
{
printf("%c ", a[k]);//用空格调位
}
printf("\n");
}
return 0;
}
12.有一行电文,一案下面规律译成密码:
即第一个字母变成第26个字母,第i个字母变成第(26-i+1)个字母,非字母字符不变。要求编程将密码译回原文,并输出密码和原文。
int main()//主函数
{
int j, n;//定义整型变量
char ch[80], tran[80];//定义字符数组
printf("输入密码:\n");//提示语句
gets_s(ch);//键盘输入
printf("\n密码是:\n%s", ch);//密码
j = 0;//赋初值
while (ch[j] != '\0')//不是最后一个字符时
{
if ((ch[j] >= 'A') && (ch[j] <= 'Z'))//ASCII中A对应的值是65,a对应的值是97
{
tran[j] = 155 - ch[j];
}
else if ((ch[j] >= 'a') && (ch[j] <= 'z'))//小写
{
tran[j] = 219 - ch[j];
}
else
{
tran[j] = ch[j];
}
j++;
}
n = j;
printf("\n输出原文:\n");//提示语句
for (j = 0; j < n; j++)//遍历输出
{
putchar(tran[j]);
}
printf("\n");//换行
return 0;//函数返回值为0
}
13.编写一个程序,将两个字符串连接起来,不要使用strcat函数。
int main()
{
char str1[120],str2[120]; //char数组大小最大为120
int i=0,j=0;
printf("请输入第一个字符串:");
scanf("%s",str1); //因要给整个数组输入字符,不需要带&地址符,带&特指某一位
printf("\n请输入第二个字符串:");
scanf("%s",str2);
while(str1[i]!='\0') //检验数组位是否为空
{
i++; //不为空时,i+1
}
while(str2[j]!='\0') //检验数组位是否为空
{
str1[i]=str2[j]; //将第二个字符数组添加到第一个字符数组后面
i++;
j++;
}
str1[i]='\0';
printf("\n两个字符串连接后:%s \n",str1);
}
14.编写一个程序,将两个字符串s1和s2比较,若s1>s2,输出一个正数;若s1=s2,输出0;若s1<s2,输出一个负数。不要用strcpy函数。两个字符串用gets函数读入。输出的正数或负数的绝对值应是相比较的两个字符串相应字符的ASCII码的差值。例如,“A”与“C”相比,由于“A”<"C",应输出负数,同时由于'A'与'C'的ASCII码差值为2,因此应输出-2.同理:”And"和"Aid"比较,根据第二个字符比较结果,’n'比'i'大5,因此应输出5。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char s1[100], s2[100];
printf("请输入s1:");
gets_s(s1);
printf("请输入s2: ");
gets_s(s2);
int len1 = strlen(s1);
int len2 = strlen(s2);
int sign = 0;
int i, j, value;
for (i = 0, j = 0; (i < len1) && (j < len2); i++, j++)
{
if (s1[i] > s2[j] || s1[i] < s2[j])
{
sign = 1;
value = s1[i] - s2[j];
break;
}
}
if (len1 > len2 && sign == 0)
{
value = s1[i] - s2[j];
}
else if (len1 < len2 && sign == 0)
{
value = s1[i] - s2[j];
}
else if(len1 == len2 && sign == 0)
{
value = 0;
}
printf("结果为: %d\n", value);
return 0;
}
15.编写一个程序,将字符数组s2中的全部字符复制到字符数组s1中。不用strcpy函数。复制时,"\0"也要复制过去。'\0'后面的字符不复制。
#include<stdio.h>
#include<string.h>
int main()
{
char s1[100], s2[100];
int i;
i = 0;
printf("请输入s1:");
gets_s(s1);
printf("请输入s2:");
gets_s(s2);
for (i = 0; i <= 100; i++)
{
s1[i] = s2[i];
if (s2[i] == '\0')
break;
}
printf("s1=%s\n",s1);
printf("s2=%s",s2);
}