个人知识库 个人知识库
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub

Agnes001

坚持是一件很伟大的事业
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub
  • C语言

    • 内存
    • 数组
      • 1 一维数组
        • 1.1 整数数组
        • 1.2 字符数组
        • 1.3 字符串数组
        • 1.4 字符串常量
      • 2 二维数组
        • 2.1 数组表示
        • 2.2 指向数组的指针表示
      • 3 柔性数组
        • 3.1 什么是柔性数组?
        • 3.2 柔性数组有什么用途 ?
        • 3.3 用法
    • 指针
    • 字符串
    • 预处理
    • 结构和联合
    • 文件操作
    • 标准函数库
    • C语言总结
  • CPlusPlus

  • Lua技术栈

  • edoyun

  • 内存管理

  • 数据结构

  • 网络编程

  • Linux

  • 池化技术

  • 操作系统

  • python

  • 编程技术
  • C语言
Agnes001
2021-03-27

数组

# 1 一维数组

结论:
1.数组名单独放在sizeof内部,数组名表示整个数组,所以sizeof(数组名)计算的是数组总大小,单位是字节
2.&数组名,数组名表示整个数组,所以&数组名取出的是整个数组的地址
3.除此之外,所有的数组名都表示首元素的地址,即指针

# 1.1 整数数组

#include<stdio.h>
int main()
{
	//一维数组
	int a[] = { 1, 2, 3, 4 };
	printf("%d\n", sizeof(a));//16  
	//1.数组名单独放在sizeof内部,数组名表示整个数组,所以sizeof(数组名)计算的是是数组总大小,单位是字节
	//2.&数组名,数组名表示整个数组,所以&数组名取出的是整个数组的地址
	//3.除此之外,所有的数组名都表示首元素的地址
	printf("%d\n", sizeof(a + 0));//4    a代表首元素地址,a+i代表第i个元素的地址,在32位平台下所有的地址的大小都是4个字节
	printf("%d\n", sizeof(*a));//4       a是首元素地址,*a是首元素--1,int型占4个字节大小
	printf("%d\n", sizeof(a + 1));//4    a是首元素地址,a+1是第二个元素的地址,它还是一个地址
	printf("%d\n", sizeof(a[1]));//4     a[1]--第二个元素
	printf("%d\n", sizeof(&a));//4       &a虽然取出的是整个数组的地址,但它还是一个地址
	printf("%d\n", sizeof(*&a));//16     &a取出的是整个数组的地址,对它进行解引用,就是这个数组,这个数字的大小就是16
	printf("%d\n", sizeof(&a + 1));//4   &a取出的是整个数组的地址,加1跳过了整个数组(16个字节),但它还是一个地址
	printf("%d\n", sizeof(&a[0]));//4    &a[0]取的是第一个元素的地址
	printf("%d\n", sizeof(&a[0] + 1));//4   &a[0] + 1取的是第二个元素的地址

	return 0;
}

# 1.2 字符数组

#include<stdio.h>
int main()
{
	//字符数组
	char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\n", sizeof(arr));//6
	printf("%d\n", sizeof(arr + 0));//4        首元素地址
	printf("%d\n", sizeof(*arr));//1           首元素地址解引用是首元素(a),char类型占1个字节
	printf("%d\n", sizeof(arr[1]));//1         首元素
	printf("%d\n", sizeof(&arr));//4           数组的地址
	printf("%d\n", sizeof(&arr + 1));//4       下一个数组的地址,跳过了f
	printf("%d\n", sizeof(&arr[0] + 1));//4    第二个元素的地址

    printf("%d\n", strlen(arr));//随机值       strlen()求的是字符串长度,以'\0'为结束标志,这里并没有'\0',所以会一直往后数
	printf("%d\n", strlen(arr + 0));//随机值   还是从'a'开始数,但没有'\0',所以停不下来
	printf("%d\n", strlen(*arr));//程序会崩掉  strlen()接收的是一个地址,*arr是字符'a',这里把'a'的ASCII码值(97)作为一个地址访问,这一块的地址是不能被访问的
	printf("%d\n", strlen(arr[1]));//错误      传的是'b',和传的是'a'效果一样
	printf("%d\n", strlen(&arr));//随机值      &arr虽然取的是数组的地址,但数组的地址和数组首元素的地址是一样的,也是从‘a'开始数,但并没有'\0'
	printf("%d\n", strlen(&arr + 1));//随机值  但这个随机值和前边的随机值意义不同,它是把'a','b','c','d','e','f'跳过去了,从f后边开始数
	printf("%d\n", strlen(&arr[0] +1));//随机值   这个是从'b'开始往后数的

	return 0;
}

# 1.3 字符串数组

#include<stdio.h>
int main()
{
    char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//7   里边还有'\0',只不过我们看不到而已
	printf("%d\n", sizeof(arr + 0));//4     arr+0---首元素地址
	printf("%d\n", sizeof(*arr));//1   对首元素地址解引用是首元素
	printf("%d\n", sizeof(arr[1]));//1 第二个元素
	printf("%d\n", sizeof(&arr));//4    数组的地址也是地址
	printf("%d\n", sizeof(&arr + 1));//4  也是一个地址,不过这个地址在'\0'后边,跳过了整个数组
	printf("%d\n", sizeof(&arr[0] + 1));//4   从b开始的一个地址
	printf("%d\n", strlen(arr));//6   strlen()以'\0'为结束标志,但不算'\0'
	printf("%d\n", strlen(arr + 0));//6  arr+0与arr都代表首元素地址
	printf("%d\n", strlen(*arr));//错误   这传进来的不是一个地址,而是一个字符
	printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr));//6    数组的地址也是首元素地址,地址的位置是一样的
	printf("%d\n", strlen(&arr + 1));//随机值   跳过了'\0',从'\0'往后数,不知道会数到哪里去
	printf("%d\n", strlen(&arr[0] + 1));//5    从第二个元素(b)开始往后数,遇到'\0'结束

	return 0;
}

# 1.4 字符串常量

#include<stdio.h>
int main()
{
    char *p = "abcdef";
	printf("%d\n", sizeof(p));//4   p是指针变量,里边存的是a的地址
	printf("%d\n", sizeof(p + 1));//4   还是一个地址,不过是指向了b的地址
	printf("%d\n", sizeof(*p));//1      对a的地址解引用就是a
	printf("%d\n", sizeof(p[0]));//1    第一个元素(a)
	printf("%d\n", sizeof(&p));//4      &p取的是p的地址,p是一个指针,指向a的地址,但p的地址是什么并不知道
	printf("%d\n", sizeof(&p + 1));//4  &p+1--跳过了p的一个地址
	printf("%d\n", sizeof(&p[0] + 1));//4   还是一个地址,这个地址指向了b的地址

    printf("%d\n", strlen(p));//6        从a开始向后数
	printf("%d\n", strlen(p + 1));//5    从b开始向后数
	printf("%d\n", strlen(*p));//错误    *p就是a,strlen()要的是一个地址,而不是a的ASCII码值(97)
	printf("%d\n", strlen(p[0]));//错误
	printf("%d\n", strlen(&p));//随机值
	printf("%d\n", strlen(&p + 1));//随机值
	printf("%d\n", strlen(&p[0] + 1));//5    从b开始往后数
	return 0;
}

# 2 二维数组

# 2.1 数组表示

#include<stdio.h>
int main()
{    
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//48    整个数组有12个元素,每个元素都是int型
	printf("%d\n", sizeof(a[0][0]));//4   代表的是第一行第一列那个元素
	printf("%d\n", sizeof(a[0]));//16   a[0]--第一行数组名,第一行总共有4个元素
	printf("%d\n", sizeof(a[0] + 1));//4   a[0]降级变为a[0][0]的地址,a[0]+1是a[0][1]的地址
	printf("%d\n", sizeof(a + 1));//4    a--首元素(第一行)地址,a+1--第二行地址
	printf("%d\n", sizeof(&a[0] + 1));//4    第二行地址
	printf("%d\n", sizeof(*a));//16   对第一行地址解引用就是第一行元素
	printf("%d\n", sizeof(a[3]));//16    这里有好多人会出错,认为这个数组并没有这么大,只有3行,不能访问第4行,其实这里并没有访问第4行,它只是一个类型(1行的大小)
	return 0;
}

# 2.2 指向数组的指针表示

int matrix[3][10];
matrix 是指向它第1个元素的指针,而第一个元素是包含10个元素的数组,所以matrix是一个指向一个包含10个整型元素的数组的指针。
matrix+1  指向matrix的第二行包含10个整型元素的数组的指针
*(matrix+1) 标识了一个包含10个整型元素的子数组,指向该数组的第一个元素,即指向整型的指针
*(matrix+1)+ 5 指向当前数组的第六个元素
*(*(matrix+1)+ 5) 

提示

数组名是一个指向第1维第1个元素的指针,所以第1个下标值根据该元素的长度进行调整。它的结果是一个指向那一维中所需元素的指针。间接访问操作随后选择那个特定的元素。由于该元素本身是个数组,所以整个表达式的类型是一个指向下一维的第1个元素的指针。下一个指标值根据这个长度进行调整,这个过程重复进行,直到所有的下标均计算完毕。

# 3 柔性数组

# 3.1 什么是柔性数组?

柔性数组既数组大小待定的数组, C语言中结构体的最后一个元素可以是大小未知的数组,也就是所谓的0长度,所以我们可以用结构体来创建柔性数组。

# 3.2 柔性数组有什么用途 ?

它的主要用途是为了满足需要变长度的结构体,为了解决使用数组时内存的冗余和数组的越界问题。

# 3.3 用法

在一个结构体的最后 ,申明一个长度为空的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,我们可以进行动态分配,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!

对于柔性数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:

typedef struct _SoftArray
{
    int len;
    int array[];
}SoftArray;

这样的变长数组常用于网络通信中构造不定长数据包,不会浪费空间浪费网络流量,比如我要发送1024字节的数据,如果用定长包,假设定长包的长度为2048,就会浪费1024个字节的空间,也会造成不必要的流量浪费。

#include <stdio.h>
int main()
{
  int arrA[2];
  printf("&arrA     : %0x\n", &arrA);     //61fe18
  printf("&arrA + 1 : %0x\n", &arrA + 1); //61fe20 
  printf("arrA      : %0x\n", arrA);      //61fe18
  printf("arrA + 1  : %0x\n", arrA + 1);  //61fe1c

  int arrB[2][2];
  printf("&arrB     : %0x\n", &arrB);     //61fe00  int (*)[2][2]
  printf("&arrB + 1 : %0x\n", &arrB + 1); //61fe10 
  printf("arrB      : %0x\n", arrB);      //61fe00  int (*)[2]
  printf("arrB + 1  : %0x\n", arrB + 1);  //61fe08  
  printf("arrB[0]   : %0x\n", arrB[0]);   //61fe00  int *
  printf("arrB[0]+1 : %0x\n", arrB[0]+1); //61fe04
  printf("&arrB[0]  : %0x\n", &arrB[0]);  //61fe00  int (*)[2]
  printf("&arrB[0]+1: %0x\n", &arrB[0]+1);//61fe08

  return 0;
}
编辑此页
#array
内存
指针

← 内存 指针 →

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式