C++中的指针和数组

简介: -------------------------------------------Section 0 前言-------------------------------------------写个简单的yuv读取的库,卡在多维数组动态分配的问题上。
 

-------------------------------------------Section 0 前言-------------------------------------------
写个简单的yuv读取的库,卡在多维数组动态分配的问题上。唉,还是C基本功不扎实,于是花了一下午时间,算是给自己有了点交代。参考《C专家编程》。水平有限,欢迎看客指正。


-------------------------------------------Section 1 左值与右值-------------------------------------
编译器为每个变量分配一个地址(左值),该地址在编译时可知,且变量在运行时一直存于该地址。存于该地址的变量的值(右值)只有在运行时可知。因此,编译器如果需要一个地址来执行某种操作,它可以直接进行操作,如果需要一个变量的值,它需要发出指令从指定地址中读入变量值并存于寄存器中。到这里,可以理解作为一个指针变量,它本身的地址是左值,它变量的值(即指向的地址值)为右值。所以指针首先需要在运行时取得它的当前值,然后才能对它进行解除引用操作。

数组名是一个左值,即内存中的位置。但数组名是一个不可修改的左值,即不可被赋值。
           int main()
           {
            int a[3] = {0};
            int b    = 1;
            a = &b; //ERROR: “=” : 左操作数必须为 l 值。
            return 0;
           }

-----------------------------------------Section 2 数组与指针的不同---------------------------------
一个例子:
           int main()
           {
            char arr[4] = "abc";                       // Note 1
            //char arr[4] = {'a', 'b', 'c', '\0'};         // Note 2
            char *ptr   = "ABC";                       // Note 3

            //ptr+1 = &arr[2];                           // Note 4

            printf("arr: %x, %x, %x %x \n", &arr, &arr[0], &arr[1]);   //Note 5
            printf("ptr: %x, %x, %x %x \n", &ptr, &ptr[0], &ptr[1]);
            return 0;
           }
Note 1&2等价定义,其结构如下:
            a    b    c    \0
           [__] [__] [__] [__]
          12fed4 +1   +2   +3

Note 3结构如下
          42703c      A    B    C    \0
           [__]      [__] [__] [__] [__]
          12fec8    42703c +1   +2   +3

Note 4复习一下Section 1。显然的错误,因为p+1首先需要知道p的值(右值),只有在运行时刻才能得到,编译时刻就希望对其所在的地址进行赋值显然错误。

Note 5验证Note1和3,运行结果如下:
           arr: 12fed4, 12fed4, 12fed5
           ptr: 12fec8, 42703c, 42703d
可以发现,arr的地址(左值)的结果与数组中首元素的地址一致,而ptr的变量值(右值)与数组的首元素地址一致。

因此对一个数组中的元素进行引用,c=arr[i]和c=ptr[i]都能够取出相应数组中的第i个元素。但要注意这两个操作的过程完全不同:
                         c = arr[i];                         c = ptr[i];
                                                      1:取地址12fec8的内容,即42703c
                   1 取出i的值与12fed4相加            2:取出i的值与42703c相加
                   2 取地址(12fed4+ i)的内容          3:取地址(42703c+i)的内容
                  
得到结论:尽管c=arr[i]和c=ptr[i]用同样的形式完成了同样的功能,但绝不可以混用。注意数组原始的声明方式,如果原始声明为数组式的,那么对其元素的引用要使用数组形式,反之亦然。
文件1中:
    int array[100];
文件2中:
    extern int *array;
    array[50] = 3;  //知道这句为什么错了吧?

-----------------------------------------Section 3 数组与指针的相同----------------------------------
传说有三种情况下,数组名会被当作指针。

1 “表达式中的数组名”就是指针
            int a[10], *p, i;
            p = a;  //here

2 数组下标就是指针的偏移量
以下语句功能一致,但需注意实现的过程不一样(Section 2):
            a[i] = 0;
            p[i] = 0;
            *(p+i) = 0;

3 函数形参中的数组名被当作指向第一个元素的指针
以下三种函数声明的形式是等同的:
            my_function(int *p) {...}
            my_function(int p[]) {...}
            my_function(int p[100]) {...}
对my_function函数的调用,无论实参是数组还是指针,都是合法的。

----------------------------------------------Section 4 多维数组-------------------------------------
首先理解一个简单的多维数组:
           int main()
           {
            int apricot[2][3][5];
            int (*p)[3][5] = apricot;  // 别忘记“表达式中的数组名”就是指针
            int (*r)[5]    = apricot[1];
            int *t         = apricot[1][2];
            int u          = apricot[1][2][3];
            return 0;
           }
根据数组下标规则不难理解,apricot[i][j][k]将被编译器解析为(*(*(apricot+i)+j)+k)。而且多维数组在内存中的布局是线性形式的,所以可以得到apricot[i][j][k]可以通过计算*(&apricot + i*3*5 + j*5 + k)得到。

另一种实现方法是使用指针数组或指针的指针。这种方式的特点是灵活,并且可以实现动态分配多维数组。
           char *pea[4];
           char **pea;
仍然可以通过pea[i][j]来引用其中的变量以及上述的内存位置计算方法(注意是否满足连续线性内存布局)。但这时需要注意的是对这种变量的初始化工作有一点技巧性,因为需要保证指针在后续的使用过程中都是合法的。常用方法是循环malloc
           for(j = 0; j < 4; j++)
            pea[j] = malloc[6];
或一次性malloc一整块数据,然后用循环将指针指向各个区域:
           malloc(row * column * sizeof(char));

最后来两个我的yuvlib里的子程序,看懂了指针就过关了。
            ************************************************************************
            * \brief
            *    Allocate 2D memory array -> unsigned char array2D[rows][columns]
            *
            * \par Output:
            *    memory size in bytes
            ************************************************************************/
           int get_mem2D(byte ***array2D, int rows, int columns)
           {
            int i;
          
            if((*array2D      = (byte**)malloc(rows*sizeof(byte*))) == NULL)
             exit(2);
            if(((*array2D)[0] = (byte* )malloc(columns*rows*sizeof(byte ))) == NULL)
             exit(2);
          
            for(i=1;i<rows;i++)
             (*array2D)[i] = (*array2D)[i-1] + columns ;
          
            return rows*columns;
           }
          
           /*!
            ************************************************************************
            * \brief
            *    free 2D memory array
            *    which was alocated with get_mem2D()
            ************************************************************************
            */
           void free_mem2D(byte **array2D)
           {
             if (array2D)
             {
               if (array2D[0])
                 free (array2D[0]);
               else exit(6);
          
               free (array2D);
             } else
             {
               exit(6);
             }
           }

目录
相关文章
|
8月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
98 3
|
6月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
106 5
|
7月前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
216 1
|
8月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
8月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
8月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
8月前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
8月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
177 4
|
8月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
484 4
|
8月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
97 2