文章目录
一、二维数组:
int arr[10] = {1,2,3,5,6,7};
{1,2,3,5,6,7};
{1,2,3,5,6,7};
{1,2,3,5,6,7};
{1,2,3,5,6,7};
定义语法:
int arr[2][3] =
{
{2, 5, 8},
{7, 9 10}
};
int arr[3][5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};
打印:
for(i = 0; i < 3; i++) // 行
{
for(j = 0; j <5; j++) // 列
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
1.大小:
数组大小: sizeof(arr);
一行大小: sizeof(arr[0]): 二维数组的一行,就是一个一维数组。
一个元素大小:sizeof(arr[0][0]) 单位:字节
行数:row = sizeof(arr)/ sizeof(arr[0])
列数:col = sizeof(arr[0])/ sizeof(arr[0][0]):就是看一行里面有多少个元素。
2.地址合一:
printf("%p\n", arr); == printf("%p\n", &arr[0][0]); == printf("%p\n", arr[0]);
数组的首地址 == 数组的首元素地址 == 数组的首行地址。
一行就相当于一个一维数组,一维数组名就相当于第一个元素的地址。我觉得这个应该叫做指针,一维数组名是一个指针变量,用来存放地址。
数组的首元素,行的首元素,数组名是三个指针变量,但是他们指向的地址是相同的。
3.二维数组的初始化:
1)常规初始化:
int arr[3][5] = {{2, 3, 54, 56, 7 }, {2, 67, 4, 35, 9}, {1, 4, 16, 3, 78}};
2) 不完全初始化:
int arr[3][5] = {{2, 3}, {2, 67, 4, }, {1, 4, 16, 78}}; 未被初始化的数值为 0
int arr[3][5] = {0}; 初始化一个 初值全为0的二维数组
int arr[3][5] = {2, 3, 2, 67, 4, 1, 4, 16, 78}; 【少见】 系统自动分配行列。
3)不完全指定行列初始化:
int arr[][] = {1, 3, 4, 6, 7}; 二维数组定义必须指定列值。
int arr[][2] = { 1, 3, 4, 6, 7 }; 可以不指定行值。
练习:求出5名学生3门功课的总成绩。(一个学生的总成绩。一门功课的总成绩)
int scores[5][3];
int row = sizeof(scores) / sizeof(scores[0]);
int col = sizeof(scores[0]) / sizeof(scores[0][0]);
// 获取 5 名学生、3门功课成绩
for (size_t i = 0; i < row; i++)
{
for (size_t j = 0; j < col; j++)
{
scanf("%d", &scores[i][j]);
}
}
// 求一个学生的总成绩
for (size_t i = 0; i < row; i++) // 每个学
{
int sum = 0;
for (size_t j = 0; j < col; j++)// 每个学生的成绩
{
sum += scores[i][j];
}
printf("第%d个学生的总成绩为:%d\n", i+1, sum);
}
//求一门功课的总成绩
for (size_t i = 0; i < col; i++) // 第几门功课
{
int sum = 0;
for (size_t j = 0; j < row; j++) // 每门功课的第几个学生
{
sum += scores[j][i];
}
printf("第%d门功课的总成绩为:%d\n", i + 1, sum);
}
快捷导入代码:
VS --》 工具--》 代码片段管理器 --》 Visual C++
4.多维数组:【了解】
三维数组:[层][行][列]
数组类型 数组名[层][行][列];
int arr[3][3][4];
{ {12, 3, 4, 5}
{12, 3, 4, 5} },
{ {12, 3, 4, 5}
{12, 3, 4, 5} },
{ {12, 3, 4, 5}
{12, 3, 4, 5} },
for(i = 0; i < 3; i++) 层
for (j = 0; j < 3; j++) 行
for (k = 0; k<4; k++) 列
printf("%d ", arr[i][j][k]);
4维、5维、6维。。。N维。
int arr[10];
short arr[20];
long long arr[20];
二、字符串:
1.字符数组和字符串的区别
在初始化的时候,字符串末尾要有结束符’\0’,而字符数组可以没有。
字符数组:
char str[5] = {'h', 'e', 'l', 'l', 'o'};
字符串:
char str[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
char str[6] = "hello";
printf("%s"); 使用printf打印字符串的时候,必须碰到 \0 结束。这是 printf 的特性。
练习:键盘输入字符串,存至str[]中,统计每个字母出现的次数。
#include <stdio.h>
#include <string.h>
int main()
{
char str[51];
printf("输入一个字符串。\n");
scanf("%s",str);
printf("输入的字符串为:%s。\n",str);
int i;
int small[26]={0};
int big[26]={0};
for(i=0; i<strlen(str); i++)
{
if( 97<=str[i]&&str[i]<=122 )
small[str[i]-97]++;
if( 65<=str[i]&&str[i]<=90 )
big[str[i]-65]++;
}
for(i=0; i<26; i++)
{
if( small[i] != 0 )
{
// 打印字母是小标i,不是small[i]
printf("%c 出现了%d次。\n",i+97,small[i]);
}
if( big[i]!= 0 )
{
printf("%c 出现了%d次。\n",i+65,big[i]);
}
}
return 0;
}
2.字符串获取 scanf:
注意: 1)用于存储字符串的空间必须足够大,防止溢出。 char str[5];
2) 获取字符串,%s, 遇到空格 和 \n 终止。
借助“正则表达式”, 获取带有空格的字符串:scanf("%[^\n]", str);
3.字符串操作函数:
gets: 从键盘获取一个字符串, 返回字符串的首地址。 可以获取带有 空格的字符串。 【不安全】
char *gets(char *s);
参数:用来存储字符串的空间地址。
返回值:返回实际获取到的字符串首地址。
fgets: 从stdin获取一个字符串, 预留 \0 的存储空间。空间足够读 \n, 空间不足舍弃 \n 【安全】
char *fgets(char *s, int size, FILE *stream);
参1:用来存储字符串的空间地址。
参2:描述空间的大小。
参3:读取字符串的位置。 键盘 --》 标准输入:stdin
返回值:返回实际获取到的字符串首地址。
puts:将一个字符串写出到屏幕. printf("%s", "hello"); / printf("hello\n"); / puts("hello"); 输出字符串后会自动添加 \n 换行符。
int puts(const char *s);
参1:待写出到屏幕的字符串。
返回值: 成功:非负数 0。 失败: -1.
fputs:将一个字符串写出到stdout.输出字符串后, 不添加 \n 换行符。
int fputs(const char * str, FILE * stream);
参1:待写出到屏幕的字符串。 屏幕 --》标准输出: stdout
参数:写出位置 stdout
返回值: 成功:0。 失败: -1.
strlen: 碰到 \0 结束。注意strlen 与sizeof 的区别,strlen是求字符串的有效长度,就是数一个字符串中有多少个字符,一直数到’\0’ 前一个字符,不包括 ‘\0’。而 sizeof 求的是一个数据占用的内存空间,如果用着来求字符串占用的内存空间,那么也将 ‘\0’ 算进去。
size_t strlen(const char *s);
参1: 待求长度的字符串
返回:有效的字符个数。
(1)fgets 是否读取’\n’测试
char str[101];
printf("输入的字符串为%s\n",fgets(str,10,stdin));
return 0;
4.字符串追加:
char str1[] = "hello";
char str2[] = "world";
char str3[100] = {0};
int i = 0; // 循环 str1
while (str1[i] != '\0')
{
str3[i] = str1[i]; // 循环着将str1中的每一个元素,交给str3
i++;
} // str3=[h e l l o]
//printf("%d\n", i); --> 5
int j = 0; // 循环 str2
while (str2[j]) // 等价于 while(str2[j] !='\0') 等价于 while (str2[j] != 0)
{
str3[i+j] = str2[j];
j++;
} // str3=[h e l l o w o r l d]
// 手动添加 \0 字符串结束标记
str3[i + j] = '\0';
三、函数
1.函数的作用:
1. 提高代码的复用率
2. 提高程序模块化组织性。
2.函数分类:
系统库函数: 标准C库。 libc
1. 引入头文件 --- 声明函数
2. 根据函数原型调用。
用户自定义:
除了需要提供函数原型之外,还需要提供函数实现。
3.随机数:
1. 播种随机数种子: srand(time(NULL));
2. 引入头文件 #include <stdlib.h> <time.h>
3. 生成随机数: rand() % 100;
4.函数定义:
包含 函数原型(返回值类型、函数名、形参列表) 和 函数体(大括号一对, 具体代码实现)
形参列表: 形式参数列表。一定包 类型名 形参名。
int add(int a, int b, int c)
{
return a+b+c;
}
int test(char ch, short b, int arr[], int m)
5.函数调用:
包含 函数名(实参列表);
int ret = add(10, 4, 28);
实参(实际参数): 在调用是,传参必须严格按照形参填充。(参数的个数、类型、顺序) 没有类型描述符
int arr[] = {1, 3, 6};
6.函数声明:
包含 函数原型(返回值类型、函数名、形参列表) + “;”
要求 在函数调用之前,编译必须见过函数定义。否则,需要函数声明。
int add(int a, int b, int c);
隐式声明:【不要依赖】
默认编译器做隐式声明函数时,返回都为 int ,根据调用语句不全函数名和形参列表。
#include <xxx.h> --> 包含函数的声明
7.exit函数: #include <stdlib.h>
return关键字:
返回当前函数调用,将返回值返回给调用者。
exit()函数:
退出当前程序。
四、多文件编程:
将多个含有不同函数功能 .c 文件模块,编译到一起,生成一个 .exe文件。
<>包裹的头文件为系统库头文件。
""包裹的头文件为用户自定义头文件。
防止头文件重复包含:头文件守卫。
1) #pragma once --- windows中
2) #ifndef __HEAD_H__ <--- head.h
#define __HEAD_H__
.... 头文件内容
#endif