数组¶
约 1802 个字 142 行代码 1 张图片 预计阅读时间 8 分钟
一维数组¶
定义和引用
- 数组长度必须得是一个数字,不能放变量,即使那个变量有值也不行。 即:
-
引用时只能引用单个值,不能一次引用整个数组。引用其实就是访问和操作那个东西
-
数组下标越界:不可越界访问;越界访问,随意赋值
-
在内存中的存放 与前后数据:见下神奇的try:不一定 内部:index从小到大地址依次增大。从下到上排
初始化
- C语言规定只能对静态存储的数组初始化,但是课本允许对动态数组+静态数组初始化 eg:
-
不初始化:
静态数组
static arr[5]:不初始化则全是0动态数组
arr[5]:不初始化则随机数 - 部分初始化:初始化前几个,后面没有初始化的元素默认赋值为0
-
全部元素都赋值则可以省略数组长度(不建议)
神奇的try看着玩玩
//按照书上的标准,这个定义方式是错的,但是不带了改代码了......
#include<stdio.h>
int main()
{
int a = 4;
int arr[a];
for(int i = 0; i < a; i++){
arr[i] = i;
}
int b = 3;
printf("%p\n", &a); printf("%p\n", &b); printf("%p\n", &arr); //打印三个的地址
printf("%p\n",&arr[0]); printf("%p\n",&arr[3]); printf("%p\n",&arr[4]); printf("%p\n",&arr[7]); //越界访问,且发现&arr[7] ==&a
printf("%d\n",*&arr[7]);
printf("%d\n",*&a); //发现上面那个之后试试a和arr[7]是什么,发现arr[7]被赋值为a的值4
printf("%d\n",arr[9]); printf("%d\n",arr[10]); //越界访问,随意赋值
int try[5] = {1, 2};
printf("%d\n", try[3]); //初始化部分元素,后面的自动赋值0
return 0;
}
/*
输出:
a's ptr:0x7ffc2289afe4 b's ptr:0x7ffc2289afe8 arr's ptr0x7ffc2289afd0 arr[0]'s ptr:0x7ffc2289afd0 arr[3]'s ptr:0x7ffc2289afdc
arr[4]'s ptr:0x7ffc2289afe0 arr[7]'s ptr:0x7ffc2289afec
arr[7]:4 *&a:4
arr[9]:0 arr[10]:579448784
try[3]:0
示例
-
用数组计算斐波那契数列,每行打印5个数字,最后一行不满5个也要换行
# include <stdio.h> # define MAXN 46 /* 定义符号常量MAXN */ int main(void) { int i, n; int fib[MAXN] = {1, 1}; /* 初始化前两个 */ printf ("Enter n: "); scanf ("%d", &n); if(n >= 1 && n <= 46 ){ for(i = 2; i < n; i++){ fib[i] = fib[i - 1] + fib[i - 2]; } /* 学学人家怎么输出:*/ for(i = 0; i < n; i++){ printf("%6d", fib[i]); if((i + 1) % 5 == 0){ /* 每5个换行:循环变量i+1是5的倍数;注意细节i+1 */ printf("\n"); } } if(n % 5 != 0){ /* 最后不满5个换行:数学转化:最后一行和总数mod5同余 */ printf("\n"); } }else{ printf("Invalid Value.\n"); } return 0; } -
选择法排序
字符串¶
定义与初始化
-
结束符
- 有效长度:不包含‘\0' : 计算字符串长度不包括末尾0
-
结束符:'\0'
char arr[] = {'h', 'i'}不是字符串char arr[] = {'h', 'i', '\0'}orchar arr[] = {'h', 'i', 0}是字符串 -
定义字符串长度 >= 字符串有效长度 + 1
因为有结束符'\0'
开大数组:只对前面的赋值,'\0'后面的与字符串无关,字符串到'\0'即结束,故不会影响字符串的处理。
-
定义方法
-
数组 & 指针:
char str[]orchar* str都可以用来定义数组,但是两个不一样。如果要用指针:不能之后再赋值,否则将导致segmentation fault ~ -
放在一维数组中
-
使用字符串常量
-
字符串常量:就是双引号括起来的一个字符串,两种定义方式:
char str[]orchar* strchar* str:只读char str[]:也是只读,不过在堆栈区会copy一份跟他一样的字符串,这个是可以修改的 -
字符串常量不能修改(但是不能写
const) - 相同的字符串字面量初始化两不同名字的字符串常量,在一样的地址上(在代码段,是只读的)
字符串常量
在C语言中,用数组和指针定义的字符串的区别主要在于它们的存储位置和是否可以修改。
-
char* str1 = "hi";- 这里str1是一个指向字符的指针,它指向一个字符串字面量。字符串字面量存储在程序的只读数据段中,这意味着你不能修改str1指向的内容。尝试修改str1指向的字符串将导致未定义行为,通常是程序崩溃。 - 例如,以下代码是不允许的: -
char str2[] = "hi";- 这里str2是一个字符数组,它在栈上分配了足够的空间来存储字符串 "hi" 及其结尾的空字符\0。str2存储的是数组的第一个元素的地址,这意味着你可以修改str2中的字符。 - 例如,以下代码是允许的:
-
字符串字面量(
str1):字符串字面量存储在只读数据段中,这是C语言规范的一部分。编译器将字符串字面量放在只读内存区域,以防止程序修改它们。这样做的好处是可以节省内存,因为多个相同的字符串字面量可以共享同一块内存区域。 -
字符数组(
str2):字符数组是在栈上分配的,它们的生命周期仅限于定义它们的函数或代码块。字符数组的内容可以被修改,因为它们不是存储在只读内存区域。
在你提供的两个例子中:
char* str1 = "hi";-
这里的
"hi"是一个字符串常量,而str1是一个指向这个字符串常量的指针。 -
char str2[] = "hi"; - 这里的
"hi"也是一个字符串常量,但str2是一个字符数组,它在栈上分配了空间,并且包含了字符串常量的内容。尽管str2本身不是一个字符串常量,它包含了字符串常量的内容,并且这些内容在数组中是可以被修改的。
为什么
str2不是字符串常量?str2不是字符串常量,因为它是一个字符数组,它包含了字符串常量的内容,但存储在栈上,并且其内容是可以被修改的。字符串常量本身是存储在只读内存区域的,而str2只是包含了这些内容的一个可修改的副本。 -
访问
-
可以用数组,可以用指针,多用指针
-
通常涉及'\0',用它来控制
输入输出
- 用
getchar(),特定字符控制
-
直接读一个字符串
-
先读一个在读一个字符串
- 用
scanf()
-
读取(可能)含有空格的字符串:目的是通过含有空格字符串的测试点
这种方法不可以用于读取单个字符
-
scanf读一个单词:到空格/tab/回车 为止,即见到那三个就停止读入了
- %ns (n为一个整数):这次输入最多输入\(n\)个值,其他的内容停在输入流中,等待下一个scanf,这些scanf依然遵循上一条char str1[8]; char str2[8]; scanf("%3s", str1); scanf("%s", str2); printf("%s##%s", str1, str2); /* input 1234 56 --> output 123##4 input 12 345 --> output 12##345 input 12 34567789835374 --> *** stack smashing detected ***: terminated \ [1] 25177 IOT instruction (core dumped) ./wk input 123456 --> output 123##456
程序参数
main函数原型:int main(int argc, char const *argv[])
-
int argc- 含义: 表示命令行参数的数量(argument count)。
- 值:
- 包括程序名在内的参数总数。
- 至少为1(即使没有其他参数,程序名也会作为第一个参数)。
-
char const *argv[]- 含义: 表示命令行参数的数组(argument vector)。
- 值:
argv[0]: 通常是程序的名称(包括路径,取决于操作系统)。argv[1]到argv[argc-1]: 由用户提供的其他命令行参数。
- 类型:
const char* argv[]是一个字符串指针数组,表示每个参数是一个以空字符\0结尾的字符串。
- 用法:
- 可以通过索引访问每个参数。
- 如果需要将字符串参数转换为数字,可以使用函数如
atoi或strtol。
示例
#include <stdio.h>
int main(int argc, char const *argv[]) {
printf("Number of arguments: %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("Argument %d: %s\n", i, argv[i]);
}
return 0;
}
运行
假设编译生成的可执行文件为 program:
输出:
程序链接:
二维数组¶
定义和引用
- 先行数后列数
-
在内存中的存放
按行 —— 列顺序存放:先0行,再1行……每行按列顺序存放
从上到下:00,01,02,10,11,12,20,21,22……
初始化
-
分行赋值
-
按顺序每行一个括号
-
部分赋值
- 括号在:内部也可像一维的一样只赋前面几个的值,空括号代表全0
- 没or少括号:代表全0
- 顺序赋值 全写出 or 部分写出,
- 如果完整赋值,可以省略行长度
-
矩阵的术语
- 主对角线:
if(i == j) - 上三角:
if(i <= j) - 下三角:
if(i >= j) - 副对角:
if(i + j == n - 1) - 遍历上三角:
/*j的循环体:*/ j = i; j < n; j++
