首页 > 其他分享 >前端学习C语言 - 数组和字节序

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

时间:2023-06-16 16:12:10浏览次数:40  
标签:初始化 字节 int C语言 00000000 数组 printf

数组

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

一维数组

初始化

有以下几种方式对数组初始化:

// 定义一个有5个元素的数组,未初始化
int a[5];

// 定义一个有5个元素的数组,将第一个初始化0,后面几个元素默认初始化为0
int a[5] = {0};

// 定义一个有5个元素的数组,5个元素都初始化为:2,3,4,5,6
int a[5] = {2, 3, 4, 5, 6};

// 【推荐】
// 和上一种在功能上是相同的。编译器会根据初始化列表中的元素个数(5个)自动确定数组a的大小为5
int a[] = {2,3,4,5,6};

Tip:以上写法创建的数组都是不可变大小的

练习1

题目int a[5] = {1},请问 a 的每个值是多少?

#include <stdio.h>
int main() {
    // 将第一个初始化1,后面几个元素默认初始化为0
    int a[5] = {1};
    int i;
    for (i = 0; i < 5; i++) {
        printf("%d ", a[i]);
    }
    return 0;
}

输出:1 0 0 0 0

在C和C++中,当我们创建数组时,如果没有为数组的所有元素提供初始值,那么剩下未被初始化指定初始值的元素会被默认初始化。对于基本数据类型(如int、float、double等),默认情况下,未初始化的元素将被设置为0

练习2

题目:如果不对 a[5] 进行初始化,将输出什么?

#include <stdio.h>
int main() {
 -  int a[5] = {1};
 +  int a[5];
    int i;
    for (i = 0; i < 5; i++) {
        printf("%d\n", a[i]);
    }
    return 0;
}

输出随机数:

开始运行...

4198784
0
4198464
0
-2014700240

运行结束。
练习3

题目:如果将int a[5]; 提到全局作用于中,输出什么?

#include <stdio.h>
int a[5];
int main() {
    int i;
    for(i =  0; i <  5; i++){
         printf("%d ", a[i]);
     }
    return  0;
}

输出: 0 0 0 0 0

练习4

题目:这段代码有什么错误?

#include <stdio.h>

int main() {
    int i = 10;
    int a[i] = {0};

    return 0;
}

运行:

开始运行...

# 不允许初始化可变大小的对象。即 i 是可变的。
/workspace/CProject-test/main.c:5:11: error: variable-sized object may not be initialized
    int a[i] = {0};
          ^
1 error generated.

运行结束。

结论:数组长度不能是变量。

如果换成 #define 常量 还有问题吗?

#include <stdio.h>
#define i 10
int main() {
    // int i = 10;
    int a[i] = {0};
    return 0;
}

如果换成 #define 常量就正常,前面我们知道 #define 是文本替换

数组名

题目:定义一个数组a,请问 a&a[0]&a的含义是什么?

#include <stdio.h>

int  main() {
    int a[5] ={1};

    printf("%p\n", a); 
    printf("%p\n", &a[0]);
    printf("%p\n", &a);
  
    printf("-----\n");

    printf("%p\n", a +  1);
    printf("%p\n", &a[0] +  1);
    printf("%p\n", &a +  1);
    return  0;
}

运行:

开始运行...

0x7ffdfb131f00
0x7ffdfb131f00
0x7ffdfb131f00
-----
0x7ffdfb131f04
0x7ffdfb131f04
0x7ffdfb131f14

运行结束。

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 语言重写如下(函数部分后文会讲):

#include <stdio.h>
  
void bubbleSort(int arr[], int n) {
    // 比较轮数,每轮都会将一个值冒泡到正确的位置
    for (int i = 0; i < n; i++) {             // 第i轮冒泡
        for (int j = 0; j < n - i - 1; j++) { // 第i轮冒泡需要比较n-i-1次
            // 出界则为 false,不会交换
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
  
int main() {
    int arr[] = {4, 3, 2, 1};
    // 计算数组长度。sizeof(arr) - 返回数据类型或变量所占内存大小(字节);arr[0] - 一个元素的字节数。
    int length = sizeof(arr) / sizeof(arr[0]);
    bubbleSort(arr, length);
    // 输出
    for (int i = 0; i < length; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}
// Output: 1 2 3 4

字节序

字节序(Byte Order)是指在存储和表示多字节数据时,字节的顺序排列方式。

思考这样一个问题

int a[5] 有5个元素,每个元素4个字节,在内存中是一块连续的空间。表示如下:

索引 a[0] a[1] a[2] a[3] a[4]
地址 0x100 0x104 0x108 0x10C 0x110

我们可以将a[0]称作低地址a[4]称作高地址。a数组中每个元素的四个字节,最左侧字节称作低地址,最右侧字节称作高地址。就像这样:

低地址     高地址
________ ________ ________ ________

数组 a 中每个元素中是一个整数,比如 a[0] = 1,在内存中是4个字节,共32位,其二进制表示为:00000000 00000000 00000000 00000001。最左侧是高字节,最右侧是低字节,就像这样:

高字节     低字节
00000000 00000000 00000000 00000001

请问 1 的高字节(00000000)放在低地址还是高地址?

大端序和小端序

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

  • 大端序(Big Endian),低字节对应高地址,高字节对应低地址。1 对应 00000000  00000000  00000000  00000001
  • 小端序(Little Endian),低字节对应低地址,高字节对应高地址。1 对应 00000001  00000000  00000000  00000000
低地址     高地址
大端序 00000000 00000000 00000000 00000001
小端序 00000001 00000000 00000000 00000000

Tip: 不同字节序的选择涉及到如何组织和解释二进制数据。字节序的重要性体现在跨平台数据交互和网络通信上。如果两个设备使用不同的字节序,就需要进行适当的数据转换才能正确解读和处理数据

二维数组

可以理解成一维数组中每个元素又是一个一维数组。例如 a[3][4] 就像这样:

0 1 2 3
0 行
1 行
2 行

a[0]a[1]a[2],每一行就是一个一维数组。

初始化

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

  • int a[3][4]; 未初始化,数组 a 中都是随机值。请看示例:
#include <stdio.h>
  
int main() {
    int a[3][4];
  
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }
  
    return 0;
}

输出:

开始运行...

-1833069321 32764 4198917 0 
0 0 0 0 
4198848 0 4198464 0 

运行结束。
  • 部分初始化。示例如下:
// 输出:1 2 3 4 5 6 7 8 9 10 11 12
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  
// 输出:1 0 0 0 5 6 0 0 0 0 0 0
int a[3][4] = {{1}, {5, 6}};
  • 全部初始化。示例如下:
// 输出:1 2 3 4 5 6 7 8 9 10 11 12
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

// 0 0 0 0 0 0 0 0 0 0 0 0 
// 此种写法不能保证所有编译器
int a[3][4] = {}
  • 行数可以省略。以下两行代码等效:
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  
// 省略行。类似一维数组中省略元素个数。
int a[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

数组名

题目:定义一个二维数组a,请问 &a[0][0]a&a[0]&a的含义是什么?

#include <stdio.h>
  
int main() {
    int a[3][4];
  
    printf("%p\n", &a[0][0]); 
    printf("%p\n", a); 
    printf("%p\n", a[0]); 
    printf("%p\n", &a); 
  
    printf("-----\n");
  
    printf("%p\n", &a[0][0] + 1);
    printf("%p\n", a + 1);
    printf("%p\n", a[0] + 1);
    printf("%p\n", &a + 1);
  
    return 0;
}

输出:

开始运行...

0x7fffadc7d310
0x7fffadc7d310
0x7fffadc7d310
0x7fffadc7d310
-----
0x7fffadc7d314
0x7fffadc7d320
0x7fffadc7d314
0x7fffadc7d340

运行结束。

上半部分都是输出的都是 0x7fffadc7d310

下半部分每个加1,差异就显现出来。

0x7fffadc7d314 - 0x7fffadc7d310 = 0x4,转为十进制是4个字节
&a[0][0] + 1

0x7fffadc7d320 - 0x7fffadc7d310 = 0x10,转为十进制是16个字节,每个元素是4个字节,也就是4(16/4)个元素,表示一行
a + 1

0x7fffadc7d314 - 0x7fffadc7d310 = 0x4,转为十进制是4个字节
a[0] + 1

0x7fffadc7d340 - 0x7fffadc7d310 = 0x30,转为十进制是48个字节,每个元素是4个字节,也就是 12(48/4)个元素,表示整个数组
&a + 1

结论:

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

题目:数组 a[3][4],哪个不能表示a[1][1]的地址?

A、a[1] + 1
B、&a[1][1]
C、(*(a + 1)) + 1
D、a + 5

答案:D。

分析:根据上文学习,我们知道 A和B能表示,其中D是加5行,肯定错。C由于没学指针,暂时不管。

字符数组

在 C 语言中,字符串可以用字符数组来表示,即用一个数组来保存一串字符,每个字符用一个字节来存储,末尾有一个特殊的空字符 '\0' 来表示字符串的结束。

#include <stdio.h>
  
int main() {
    char str[] = {'h', 'e', 'l', 'l', 'o', '\0'};
    printf("%s", str);
  
    return 0;
}

在字符数组的初始化末尾一定要添加空字符 '\0'(笔者使用的在线编辑器没报错),否则在使用字符串函数处理字符串时,可能会出现意外的错误。也可以将上面的代码简化为以下形式:

char str[] = "hello";

这样就可以不用手动添加空字符了,编译器会自动为字符串添加结尾的空字符。

练习

题目:在输入的字符串中,在指定位置插入指定字符

实现:

#include <stdio.h>
// string.h 是 C 语言中的头文件,用于提供一些字符串处理操作的函数和宏定义
#include <string.h>
  
void insertChar(char str[], int pos, char ch) {
    // 获取字符串的长度
    int len = strlen(str);
  
    // 检查插入位置是否有效
    if (pos < 0 || pos > len)
        return;
  
    // 将指定位置后的字符往后移动一位
    for (int i = len; i >= pos; i--) {
        str[i + 1] = str[i];
    }
  
    // 在指定位置插入字符
    str[pos] = ch;
}
  
int main() {
    char str[100];
    int pos;
    char ch;
  
    printf("请输入字符串。例如 hello world:\n");
    scanf("%[^\n]", str);
    printf("请输入要插入的位置:");
    scanf("%d", &pos);
    printf("请输入要插入的字符:");
    scanf(" %c", &ch);
  
    insertChar(str, pos, ch);
  
    printf("\n修改后的字符串:%s\n", str);
  
    return 0;
}

运行:

开始运行...

请输入字符串。例如 hello world:
a-b-c d e-f-g
请输入要插入的位置:4
请输入要插入的字符:x

修改后的字符串:a-b-xc d e-f-g

运行结束。

标签:初始化,字节,int,C语言,00000000,数组,printf
From: https://www.cnblogs.com/pengjiali/p/17485725.html

相关文章

  • 字符串数组不能转化对象数组,jsonArray也转化报错
    刚开始写法------错误JSONArrayjsonArray=(JSONArray)this.getJsonFilter().get("ids");PltPayDuesModel[]payDuesModels=(PltPayDuesModel[])jsonArray.toArray();报这个[Ljava.lang.Object;cannotbecastto[Ljava.lang.String;由于无法直接,因此需要曲线救国......
  • JavaScript 数组展平方法: flat() 和 flatMap()
    JavaScript数组展平方法:flat()和flatMap()从ES2019中开始引入了一种扁平化数组的新方法,可以展平任何深度的数组。flatflat()方法创建一个新数组,其中所有子数组元素以递归方式连接到特定深度。语法:array.flat(depth)array:flat()方法将在给定的数组中使用。depth......
  • 直播平台怎么搭建,vue 中判断数组中是否有重复的数据
    直播平台怎么搭建,vue中判断数组中是否有重复的数据  isRepeat(v){   letobj={}   for(letiinv){    if(obj[v[i]]){     returntrue    }    obj[v[i]]=true   }   returnfalse  },​ 以上就是......
  • C语言-预处理
    简介C语言编译器在编译程序之前,会先使用预处理器(preprocessor)处理代码。预处理器首先会清理代码,进行删除注释、多行语句合成一个逻辑行等工作。然后,执行#开头的预处理指令。本章介绍C语言的预处理指令。预处理指令可以出现在程序的任何地方,但是习惯上,往往放在代码的开头部分。每......
  • Go-map、切片、数组循环常见问题总结
    map1、forrangemap在开始执行循环的时候,底层做了随机种子,故其循环是随机的。packagemainimport"fmt"funcmain(){ a:=map[int]int{0:1,1:2,2:3,3:4,4:5} for_,c:=rangea{ fmt.Println(c) }}输出:34512多次执行,结果不同数组packagema......
  • 【剑指Offer】13、调整数组顺序使奇数位于偶数前面
    【剑指Offer】13、调整数组顺序使奇数位于偶数前面题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。解题思路:首先,如果不考虑奇数和奇数,偶数和偶数......
  • tr069 节点模板定义c语言
    #include<stdio.h>/*Signed*/typedefsignedcharint8_t;typedefshortintint16_t;typedefintint32_t;/*Unsigned.*/typedefunsignedcharuint8_t;typedefunsignedshortintuint16_t;typedefunsignedint......
  • 多维数组转变为一维数组
    1·join和splitjoin将数组拼接为字符串 split将字符串转变为数组结果的元素为字符串,可通过map遍历处理每一项1lettemp=[1,[2,3],[4,5,[6,7]]];2letres=temp.join(',').split(',')3letres2=res.map((val,idx)=>{4returnNumber(v......
  • 数组去重的5种方法
    1·newSet解构letres1=[...newSet(arAr)]2·newSet Array.fromletres2=Array.from(newSet(arAr))3·for循环splice1letfn=(array)=>{2for(leti=0;i<array.length;i++){3for(letj=i+1;j<array.length;j++){......
  • C语言—— void 的使用
    1、voidfunc(inta,char*b)  当函数不需要返回值值时,必须使用void限定,这就是我们所说的第一种情况。2、intfunc(void)  当函数不允许接受参数时,必须使用void限定,这就是我们所说的第二种情况。3、void指针的使用规则void指针可以指向任意类型的数据,就是说可以用任意类型......