设为首页 加入收藏

TOP

关于指针、数组、字符串的恩怨,这里有你想知道的一切(一)
2023-07-23 13:28:14 】 浏览:69
Tags:关于指 数组 符串的

指针、数组、字符串的恩怨,这有你想知道的一切

内存组成

为了讲明白不同方式下数组、字符串定义时在内存中的存放方式,需要先对计算机内存分区组成有所了解:

在这里插入图片描述

堆区

堆区 (Heap):由程序员手动申请释放的内存空间。

  1. C中:malloc()colloc()函数申请,用free()释放

若不用free()释放,容易造成内存泄露(即内存被浪费、耗尽)。

  • ptr = (castType*) malloc(size);

传入参数为内存的字节数,内存未被初始化。

  • ptr = (castType*)calloc(n, size);

存入参数为内存块数与每块字节数,内存初始化为0

  • free(ptr);

释放申请的内存。

  1. C++中:new申请,delete释放。newdelete都是操作符
  • int *arr = new int[10];
  • delete[] arr;

栈区

栈区 (Stack):由系统管理,存放函数参数与局部变量。函数完成执行,系统自行释放栈区内存。

静态存储区

静态存储区 (Static Storage Area):在编译阶段分配好内存空间并初始化。

其中全局区存放静态变量(static修饰的变量)、全局变量(具有全局作用域的变量);常量区存放常量(又称为字面量)。

常量可分为整数常量(如1000L)、浮点常量(如314158E-5L)、字符常量(如'A'、'\n')和字符串常量(如"Hello")

const关键字修饰的的变量无法修改,但存放的位置取决于变量本身是全局变量还是局部变量。当修饰的变量是全局变量,则放在全局区,否则依然在栈区分配。

static关键字修饰的变量存在全局区的静态变量区。

常变量宏定义的概念不同。

常变量存储在静态存储区,初始化后无法修改。

宏定义在预处理阶段就被替换。不存在与任何内存区域。

代码区

代码区 (Code Segment):存放程序体的二进制代码。

代码示例

/*示例代码*/

int a = 0;          //静态全局变量区
char *p1;           //编译器默认初始化为NULL,存在静态全局变量区

void main()
{
    int b;                //栈
    char s[] = "abc";     //栈
    char *p1 = "123";     //"123"在字符串常量区,p1在栈区
    
    p2 = (char *)malloc(10); //堆区
    strcpy(p2, "123");       //"123"放在字符串常量区
    
    const int d = 0;      //栈
    static int c = 0;     //c在静态变量区,0为文字常量,在代码区
    static const int d;   //静态常量区
    
}

字符串定义 - 一维

方法一

char s[10] = "Hello"

内存:静态存储区上的字面量"Hello"被复制到栈区,数组在栈区上的存储方式为'H''e''l''l''o''\0',可以通过s[i]修改。但这不会影响到静态存储区上的"Hello"

定义与使用:

#include <stdio.h>

void f(char s[10]) {      //等价于char *s
    printf("%s\n", s);
}

int main() {
    char s[10] = "LeeHero";
    s[3] = 'Z';
    printf("%s\n", s);   //输出:LeeZero
    printf("%s\n", s+1); //输出:eeZero
    printf("%c\n", s[3]);//输出:Z
 
    f(s); //数组名作为函数参数传递时,会退化成指向数组首元素的指针 !IMPORTANT
    return 0;
} 

格式控制符 %s 跟随一个地址,并当做是字符串第一个元素对应的地址.

从该首地址开始解析,直到 '\0' 结束。

在这里指的是 s[0] = 'H' 的地址。

方法二

char *s = "Hello"

// 等价于const char *s = "Hello"

内存:s是指向字面量"Hello"的指针,字面量在静态内存区,因此该字符串不可被修改。

定义与使用:

#include <stdio.h>

void f(char s[10]) {       //等价于char *s
    printf("%s\n", s);
}

int main() {
    char *s = "LeeHero";
    //s[3] = 'Z';          //无法执行 
    printf("%s\n", s);     //输出:LeeHero
    printf("%s\n", s+1);   //输出:eeHero
    printf("%c\n", s[3]);  //输出:H
 
    f(s);
    
    return 0;
} 

字符串定义 - 二维

方法一

char s[10][10] = {"Hello","World"}

内存:静态存储区上的字面量"Hello""World"被拷贝在栈区,与一维定义方式同理,可以通过语法糖s[i][j]修改字符。

定义与使用:

#include <stdio.h>

void f(char (*s)[10]) {        //形参s是个指针,指向有10个元素的字符数组
                               //把(*s)[10] 改成 s[][10] ,其他不变,最后效果相同
    printf("%s\n", s[1]);      //输出:Zero
    s[1][0] = 'H';             //通过语法糖s[i][j]修改字符
    printf("%s\n", s[1]);      //输出:Hero
    printf("%c\n", s[0][1]);   //输出:e
}

int main() {
    char s[10][10] = {"Lee","Hero"};
    //s[1] = "Hey";            //无法执行,这种赋值方式仅在初始化时可用
    s[1][0] = 'Z';
    printf("%s\n", s);         //输出:Lee
    printf("%s\n", *s+1);      //输出:ee
    printf("%s\n", s[0]+1);    //输出:ee
    
    printf("%c\n", *(s[0]+1)); //输出:e
    printf("%c\n", s[0][1]);   //输出:e
    
    printf("%s\n", s+1);       //输出:Zero
    printf("%s\n", s[1]);      //输出:Zero
    
    f(s);
    
    printf("%s\n", s[1]);      //输出:Hero 这意味着函数内部的修改不是局部生效的
    return 0;
} 

对于打印结果

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇MAC QT OpenGL 图像 GPUImageLook.. 下一篇C/C++ 恨透了 double free or cor..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目