指针与数组的关系

在C语言中,指针与数组紧密相关。数组名本质上是数组首元素的地址常量,而指针是存储地址的变量。通过指针可以遍历或操作数组元素,例如:

int arr[3] = {1, 2, 3};
int *p = arr;  // p指向arr首元素
printf("%d", *(p + 1));  // 输出arr[1]的值2

指针算术允许通过增减指针值访问数组后续或前置元素。

数组指针(指向数组的指针)

数组指针指向整个数组而非单个元素,其声明需指定数组大小。常用于多维数组操作:

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = arr;  // p指向包含3个元素的数组
printf("%d", p[1][2]);  // 输出6(访问第二行第三列)

p的类型是“指向含有3个整数的数组的指针”,步长以整个一维数组为单位。

指针数组(存储指针的数组)

指针数组是元素为指针的数组,常用于管理多个字符串或动态内存:

char *names[3] = {"Alice", "Bob", "Charlie"};  // 每个元素是char*指针
for (int i = 0; i < 3; i++) {
    printf("%s\n", names[i]);  // 输出字符串
}

每个元素names[i]指向独立的字符串常量,内存布局分散。

关键区别总结

  • 指针与数组:数组名是常量指针,指针是变量,可重新赋值。

  • 数组指针:指向整个数组,步长由数组大小决定。

  • 指针数组:数组元素是指针,需单独分配或指向数据。

通过理解这三者的内存模型和操作方式,可以灵活应用于动态内存、函数参数传递等场景。

指针与数组的关系

在C语言中,指针与数组紧密相关。数组名本质上是数组首元素的地址常量,而指针是存储地址的变量。通过指针可以遍历或操作数组元素,例如:

int arr[3] = {1, 2, 3};
int *p = arr;  // p指向arr首元素
printf("%d", *(p + 1));  // 输出arr[1]的值2

指针算术允许通过增减指针值访问数组后续或前置元素。

数组指针(指向数组的指针)

数组指针指向整个数组而非单个元素,其声明需指定数组大小。常用于多维数组操作:

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = arr;  // p指向包含3个元素的数组
printf("%d", p[1][2]);  // 输出6(访问第二行第三列)

p的类型是“指向含有3个整数的数组的指针”,步长以整个一维数组为单位。

指针数组(存储指针的数组)

指针数组是元素为指针的数组,常用于管理多个字符串或动态内存:

char *names[3] = {"Alice", "Bob", "Charlie"};  // 每个元素是char*指针
for (int i = 0; i < 3; i++) {
    printf("%s\n", names[i]);  // 输出字符串
}

每个元素names[i]指向独立的字符串常量,内存布局分散。

关键区别总结

  • 指针与数组:数组名是常量指针,指针是变量,可重新赋值。

  • 数组指针:指向整个数组,步长由数组大小决定。

  • 指针数组:数组元素是指针,需单独分配或指向数据。

通过理解这三者的内存模型和操作方式,可以灵活应用于动态内存、函数参数传递等场景。

 

C语言内存管理概述

C语言的内存管理主要涉及程序运行时内存的分配、使用和释放,分为静态内存、栈内存和堆内存三种方式。程序需手动管理堆内存,避免内存泄漏或非法访问。


静态内存分配

在编译时确定内存大小,生命周期贯穿整个程序运行期。

  • 全局变量:存储在静态区,程序启动时分配,结束时释放。
    int global_var; // 全局变量
    

  • 静态局部变量:使用static关键字,作用域限于函数内,但生命周期与全局变量相同。
    void func() {
        static int count = 0; // 静态局部变量
    }
    


栈内存分配

由编译器自动管理,用于局部变量和函数调用。

  • 特点:内存分配/释放速度快,但容量有限(通常几MB)。

  • 示例
    void foo() {
        int stack_var; // 栈内存分配
    }
    

  • 注意:栈内存随函数结束自动释放,不可返回指向栈内存的指针。


堆内存分配

需手动管理,通过malloccallocreallocfree操作。

  • malloc:分配指定字节的未初始化内存。
    int *arr = (int*)malloc(10 * sizeof(int)); // 分配10个int的空间
    

  • free:释放内存,避免泄漏。
    free(arr); // 释放内存
    arr = NULL; // 避免野指针
    


常见问题与建议

  • 内存泄漏:未释放堆内存导致资源浪费。需配对使用malloc/callocfree

  • 野指针:释放后未置空指针,可能引发非法访问。释放后立即赋NULL

  • 越界访问:操作超出分配的内存范围。确保索引在合法区间内。

  • 碎片化:频繁分配/释放小块内存可能导致碎片。合理规划内存使用。

C语言内存管理概述

C语言的内存管理主要涉及程序运行时内存的分配、使用和释放,分为静态内存、栈内存和堆内存三种方式。程序需手动管理堆内存,避免内存泄漏或非法访问。


静态内存分配

在编译时确定内存大小,生命周期贯穿整个程序运行期。

  • 全局变量:存储在静态区,程序启动时分配,结束时释放。
    int global_var; // 全局变量
    

  • 静态局部变量:使用static关键字,作用域限于函数内,但生命周期与全局变量相同。
    void func() {
        static int count = 0; // 静态局部变量
    }
    


栈内存分配

由编译器自动管理,用于局部变量和函数调用。

  • 特点:内存分配/释放速度快,但容量有限(通常几MB)。

  • 示例
    void foo() {
        int stack_var; // 栈内存分配
    }
    

  • 注意:栈内存随函数结束自动释放,不可返回指向栈内存的指针。


堆内存分配

需手动管理,通过malloccallocreallocfree操作。

  • malloc:分配指定字节的未初始化内存。
    int *arr = (int*)malloc(10 * sizeof(int)); // 分配10个int的空间
    

  • calloc:分配并初始化内存为零。
    int *arr = (int*)calloc(10, sizeof(int)); // 分配且初始化为0
    

  • realloc:调整已分配内存的大小。
    arr = (int*)realloc(arr, 20 * sizeof(int)); // 扩展至20个int
    

  • free:释放内存,避免泄漏。
    free(arr); // 释放内存
    arr = NULL; // 避免野指针
    


常见问题与建议

  • 内存泄漏:未释放堆内存导致资源浪费。需配对使用malloc/callocfree

  • 野指针:释放后未置空指针,可能引发非法访问。释放后立即赋NULL

  • 越界访问:操作超出分配的内存范围。确保索引在合法区间内。

  • 碎片化:频繁分配/释放小块内存可能导致碎片。合理规划内存使用。

作业 :

        1.用指针实现二维数组的冒泡排序
 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, const char *argv[])
{
	int arr[3][4]={1,0,2,5,11,7,4,6,9,8,3,12};
	int (*ptr)[4]=NULL;
	int i,j,temp;
	ptr=arr;
	for(i=0;i<12-1;i++)
		for(j=0;j<12-i-1;j++)
			if(*(ptr[0]+j)>*(ptr[0]+j+1))
			{
				temp=*(ptr[0]+j);
				*(ptr[0]+j)=*(ptr[0]+j+1);
				*(ptr[0]+j+1)=temp;
			}
	for(i=0;i<12;i++)
		printf("%-2d ",*(ptr[0]+i));
	putchar(10);
	return 0;
}

运行结果:

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐