前端学习C语言 - 数组和字节序

打印 上一主题 下一主题

主题 1713|帖子 1713|积分 5139

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
数组

本篇主要介绍:一维二维数组、字符数组、数组名和初始化注意点以及字节序。
一维数组

初始化

有以下几种方式对数组初始化:
  1. // 定义一个有5个元素的数组,未初始化
  2. int a[5];
  3. // 定义一个有5个元素的数组,将第一个初始化0,后面几个元素默认初始化为0
  4. int a[5] = {0};
  5. // 定义一个有5个元素的数组,5个元素都初始化为:2,3,4,5,6
  6. int a[5] = {2, 3, 4, 5, 6};
  7. // 【推荐】
  8. // 和上一种在功能上是相同的。编译器会根据初始化列表中的元素个数(5个)自动确定数组a的大小为5
  9. int a[] = {2,3,4,5,6};
复制代码
Tip:以上写法创建的数组都是不可变大小的。
练习1

题目:int a[5] = {1},请问 a 的每个值是多少?
  1. #include <stdio.h>
  2. int main() {
  3.     // 将第一个初始化1,后面几个元素默认初始化为0
  4.     int a[5] = {1};
  5.     int i;
  6.     for (i = 0; i < 5; i++) {
  7.         printf("%d ", a[i]);
  8.     }
  9.     return 0;
  10. }
复制代码
输出:1 0 0 0 0。
在C和C++中,当我们创建数组时,如果没有为数组的所有元素提供初始值,那么剩下未被初始化指定初始值的元素会被默认初始化。对于基本数据类型(如int、float、double等),默认情况下,未初始化的元素将被设置为0
练习2

题目:如果不对 a[5] 进行初始化,将输出什么?
  1. #include <stdio.h>
  2. int main() {
  3. -  int a[5] = {1};
  4. +  int a[5];
  5.     int i;
  6.     for (i = 0; i < 5; i++) {
  7.         printf("%d\n", a[i]);
  8.     }
  9.     return 0;
  10. }
复制代码
输出随机数:
  1. 开始运行...
  2. 4198784
  3. 0
  4. 4198464
  5. 0
  6. -2014700240
  7. 运行结束。
复制代码
练习3

题目:如果将int a[5]; 提到全局作用于中,输出什么?
  1. #include <stdio.h>
  2. int a[5];
  3. int main() {
  4.     int i;
  5.     for(i =  0; i <  5; i++){
  6.          printf("%d ", a[i]);
  7.      }
  8.     return  0;
  9. }
复制代码
输出: 0 0 0 0 0
练习4

题目:这段代码有什么错误?
  1. #include <stdio.h>
  2. int main() {
  3.     int i = 10;
  4.     int a[i] = {0};
  5.     return 0;
  6. }
复制代码
运行:
  1. 开始运行...
  2. # 不允许初始化可变大小的对象。即 i 是可变的。
  3. /workspace/CProject-test/main.c:5:11: error: variable-sized object may not be initialized
  4.     int a[i] = {0};
  5.           ^
  6. 1 error generated.
  7. 运行结束。
复制代码
结论:数组长度不能是变量。
如果换成 #define 常量 还有问题吗?
  1. #include <stdio.h>
  2. #define i 10
  3. int main() {
  4.     // int i = 10;
  5.     int a[i] = {0};
  6.     return 0;
  7. }
复制代码
如果换成 #define 常量就正常,前面我们知道 #define 是文本替换。
数组名

题目:定义一个数组a,请问 a、&a[0]、&a的含义是什么?
  1. #include <stdio.h>
  2. int  main() {
  3.     int a[5] ={1};
  4.     printf("%p\n", a);
  5.     printf("%p\n", &a[0]);
  6.     printf("%p\n", &a);
  7.   
  8.     printf("-----\n");
  9.     printf("%p\n", a +  1);
  10.     printf("%p\n", &a[0] +  1);
  11.     printf("%p\n", &a +  1);
  12.     return  0;
  13. }
复制代码
运行:
  1. 开始运行...
  2. 0x7ffdfb131f00
  3. 0x7ffdfb131f00
  4. 0x7ffdfb131f00
  5. -----
  6. 0x7ffdfb131f04
  7. 0x7ffdfb131f04
  8. 0x7ffdfb131f14
  9. 运行结束。
复制代码
Tip: printf 中的 %p 打印的就是内存地址。内存地址通常以十六进制形式表示。
上半部分都是输出的都是 0x7ffdfb131f00。
但下半部分加1后,结果明显不同。其中:

  • 0x7ffdfb131f04 - 0x7ffdfb131f00 = 0x4,转为十进制是4,一个 int 就是4个字节
  • 0x7ffdfb131f14 - 0x7ffdfb131f00 = 0x14,转为十进制数是20,刚好是数组 a 的字节数(5*4)
结论:

  • a - 数组名。表示首元素的地址,加 1 是加一个元素(比如这里4个字节)
  • &a[0] - 表示首元素地址,加 1 是加一个元素(比如这里4个字节)
  • &a - 表示整个数组。加1相当于跨越了整个数组
冒泡排序

之前我们写过冒泡排序的例子,我们将该示例用 C 语言重写如下(函数部分后文会讲):
  1. #include <stdio.h>
  2.   
  3. void bubbleSort(int arr[], int n) {
  4.     // 比较轮数,每轮都会将一个值冒泡到正确的位置
  5.     for (int i = 0; i < n; i++) {             // 第i轮冒泡
  6.         for (int j = 0; j < n - i - 1; j++) { // 第i轮冒泡需要比较n-i-1次
  7.             // 出界则为 false,不会交换
  8.             if (arr[j] > arr[j + 1]) {
  9.                 int temp = arr[j];
  10.                 arr[j] = arr[j + 1];
  11.                 arr[j + 1] = temp;
  12.             }
  13.         }
  14.     }
  15. }
  16.   
  17. int main() {
  18.     int arr[] = {4, 3, 2, 1};
  19.     // 计算数组长度。sizeof(arr) - 返回数据类型或变量所占内存大小(字节);arr[0] - 一个元素的字节数。
  20.     int length = sizeof(arr) / sizeof(arr[0]);
  21.     bubbleSort(arr, length);
  22.     // 输出
  23.     for (int i = 0; i < length; i++) {
  24.         printf("%d ", arr[i]);
  25.     }
  26.     return 0;
  27. }
  28. // Output: 1 2 3 4
复制代码
字节序

字节序(Byte Order)是指在存储和表示多字节数据时,字节的顺序排列方式。
思考这样一个问题

int a[5] 有5个元素,每个元素4个字节,在内存中是一块连续的空间。表示如下:
索引a[0]a[1]a[2]a[3]a[4]地址0x1000x1040x1080x10C0x110我们可以将a[0]称作低地址,a[4]称作高地址。a数组中每个元素的四个字节,最左侧字节称作低地址,最右侧字节称作高地址。就像这样:
低地址  高地址________________________________数组 a 中每个元素中是一个整数,比如 a[0] = 1,在内存中是4个字节,共32位,其二进制表示为:00000000 00000000 00000000 00000001。最左侧是高字节,最右侧是低字节,就像这样:
高字节  低字节00000000000000000000000000000001请问 1 的高字节(00000000)放在低地址还是高地址?
大端序和小端序

不同的计算机架构和处理器采用不同的字节序(Byte Order)。常见的字节序有两种:

  • 大端序(Big Endian),低字节对应高地址,高字节对应低地址。1 对应 00000000  00000000  00000000  00000001
  • 小端序(Little Endian),低字节对应低地址,高字节对应高地址。1 对应 00000001  00000000  00000000  00000000
低地址  高地址大端序00000000000000000000000000000001小端序00000001000000000000000000000000Tip: 不同字节序的选择涉及到如何组织和解释二进制数据。字节序的重要性体现在跨平台数据交互和网络通信上。如果两个设备使用不同的字节序,就需要进行适当的数据转换才能正确解读和处理数据
二维数组

可以理解成一维数组中每个元素又是一个一维数组。例如 a[3][4] 就像这样:
01230 行1 行2 行a[0]、a[1]、a[2],每一行就是一个一维数组。
初始化

有多种方式进行二维数组的初始化,效果也不尽相同。请看示例:

  • int a[3][4]; 未初始化,数组 a 中都是随机值。请看示例:
  1. #include <stdio.h>
  2.   
  3. int main() {
  4.     int a[3][4];
  5.   
  6.     for (int i = 0; i < 3; i++) {
  7.         for (int j = 0; j < 4; j++) {
  8.             printf("%d ", a[i][j]);
  9.         }
  10.         printf("\n");
  11.     }
  12.   
  13.     return 0;
  14. }
复制代码
输出:
  1. 开始运行...
  2. -1833069321 32764 4198917 0
  3. 0 0 0 0
  4. 4198848 0 4198464 0
  5. 运行结束。
复制代码

  • 部分初始化。示例如下:
  1. // 输出:1 2 3 4 5 6 7 8 9 10 11 12
  2. int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  3.   
  4. // 输出:1 0 0 0 5 6 0 0 0 0 0 0
  5. int a[3][4] = {{1}, {5, 6}};
复制代码

  • 全部初始化。示例如下:
  1. // 输出:1 2 3 4 5 6 7 8 9 10 11 12
  2. int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  3. // 0 0 0 0 0 0 0 0 0 0 0 0
  4. // 此种写法不能保证所有编译器
  5. int a[3][4] = {}
复制代码

  • 行数可以省略。以下两行代码等效:
  1. int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  2.   
  3. // 省略行。类似一维数组中省略元素个数。
  4. int a[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
复制代码
数组名

题目:定义一个二维数组a,请问 &a[0][0]、a、&a[0]、&a的含义是什么?
  1. #include <stdio.h>
  2.   
  3. int main() {
  4.     int a[3][4];
  5.   
  6.     printf("%p\n", &a[0][0]);
  7.     printf("%p\n", a);
  8.     printf("%p\n", a[0]);
  9.     printf("%p\n", &a);
  10.   
  11.     printf("-----\n");
  12.   
  13.     printf("%p\n", &a[0][0] + 1);
  14.     printf("%p\n", a + 1);
  15.     printf("%p\n", a[0] + 1);
  16.     printf("%p\n", &a + 1);
  17.   
  18.     return 0;
  19. }
复制代码
输出:
  1. 开始运行...
  2. 0x7fffadc7d310
  3. 0x7fffadc7d310
  4. 0x7fffadc7d310
  5. 0x7fffadc7d310
  6. -----
  7. 0x7fffadc7d314
  8. 0x7fffadc7d320
  9. 0x7fffadc7d314
  10. 0x7fffadc7d340
  11. 运行结束。
复制代码
上半部分都是输出的都是 0x7fffadc7d310。
下半部分每个加1,差异就显现出来。
  1. 0x7fffadc7d314 - 0x7fffadc7d310 = 0x4,转为十进制是4个字节
  2. &a[0][0] + 1
  3. 0x7fffadc7d320 - 0x7fffadc7d310 = 0x10,转为十进制是16个字节,每个元素是4个字节,也就是4(16/4)个元素,表示一行
  4. a + 1
  5. 0x7fffadc7d314 - 0x7fffadc7d310 = 0x4,转为十进制是4个字节
  6. a[0] + 1
  7. 0x7fffadc7d340 - 0x7fffadc7d310 = 0x30,转为十进制是48个字节,每个元素是4个字节,也就是 12(48/4)个元素,表示整个数组
  8. &a + 1
复制代码
结论:

  • &a[0][0] - 首行首元素地址,加 1 是加一个元素(比如这里4个字节)
  • a - 地址名,表示首行地址,加 1 就是加一行
  • a[0] - 首行首元素地址,加 1 是加一个元素(比如这里4个字节)
  • &a - 表示整个数组。加1相当于跨越了一个数组
练习

题目:数组 a[3][4],哪个不能表示a[1][1]的地址?
  1. A、a[1] + 1
  2. B、&a[1][1]
  3. C、(*(a + 1)) + 1
  4. D、a + 5
复制代码
答案:D。
分析:根据上文学习,我们知道 A和B能表示,其中D是加5行,肯定错。C由于没学指针,暂时不管。
字符数组

在 C 语言中,字符串可以用字符数组来表示,即用一个数组来保存一串字符,每个字符用一个字节来存储,末尾有一个特殊的空字符 '\0' 来表示字符串的结束。
  1. #include <stdio.h>
  2.   
  3. int main() {
  4.     char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};
  5.     printf("%s", str);
  6.   
  7.     return 0;
  8. }
复制代码
在字符数组的初始化末尾一定要添加空字符 '\0'(笔者使用的在线编辑器没报错),否则在使用字符串函数处理字符串时,可能会出现意外的错误。也可以将上面的代码简化为以下形式:
  1. char str[] = "hello";
复制代码
这样就可以不用手动添加空字符了,编译器会自动为字符串添加结尾的空字符。
练习

题目:在输入的字符串中,在指定位置插入指定字符
实现:
  1. #include <stdio.h>
  2. // string.h 是 C 语言中的头文件,用于提供一些字符串处理操作的函数和宏定义
  3. #include <string.h>
  4.   
  5. void insertChar(char str[], int pos, char ch) {
  6.     // 获取字符串的长度
  7.     int len = strlen(str);
  8.   
  9.     // 检查插入位置是否有效
  10.     if (pos < 0 || pos > len)
  11.         return;
  12.   
  13.     // 将指定位置后的字符往后移动一位
  14.     for (int i = len; i >= pos; i--) {
  15.         str[i + 1] = str[i];
  16.     }
  17.   
  18.     // 在指定位置插入字符
  19.     str[pos] = ch;
  20. }
  21.   
  22. int main() {
  23.     char str[100];
  24.     int pos;
  25.     char ch;
  26.   
  27.     printf("请输入字符串。例如 hello world:\n");
  28.     scanf("%[^\n]", str);
  29.     printf("请输入要插入的位置:");
  30.     scanf("%d", &pos);
  31.     printf("请输入要插入的字符:");
  32.     scanf(" %c", &ch);
  33.   
  34.     insertChar(str, pos, ch);
  35.   
  36.     printf("\n修改后的字符串:%s\n", str);
  37.   
  38.     return 0;
  39. }
复制代码
运行:
  1. 开始运行...
  2. 请输入字符串。例如 hello world:
  3. a-b-c d e-f-g
  4. 请输入要插入的位置:4
  5. 请输入要插入的字符:x
  6. 修改后的字符串:a-b-xc d e-f-g
  7. 运行结束。
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表