代码之家  ›  专栏  ›  技术社区  ›  Edher Carbajal

多指针分配是否会导致溢出?

  •  0
  • Edher Carbajal  · 技术社区  · 2 年前

    我正试图用C来理解记忆管理。到目前为止,我有一个清晰的概述,但有一个问题对我来说并不那么明显。

    如果我申报 char 指针并为其分配一些字符串,然后指针包含该字符串的地址(分配给somhere)。

    char *pchar1 = "Hello World OLD";
    unsigned long x = (unsigned long)pchar1; //Note that I'm storing the value of this addr for further usage
    printf("pchar1 content: %s\n", pchar1); // Hello World OLD
    printf("Adress of pchar1: %lu\n\n", pchar1); //<Some Random Addr>
    

    如果我给指针分配另一个字符串,那么它将指向另一个地址。

    pchar1 = "Hello World NEW";
    printf("pchar1 content: %s\n", pchar1); // Hello World NEW
    printf("Adress of pchar1: %lu\n\n", pchar1); // <A different addrs than the fisrt one>
    

    如果我试着读取旧的内存位置,我发现仍然有我的旧字符串

    printf("Old addr stores in 'x': %lu\n", x); // Hello World OLD
    printf("Reading old pchar1 mem addr (from x): %s\n\n", (char *)x); // <The First Address>
    

    我的问题是,正如记忆所用 没有被释放 如果我不存储旧内存addr的值,那么 我记不清了 ,这样的东西可能会导致溢出吗?

    while(1){
            pchar1 = "Hello World OLD"; //Stores this string in a different addres
            pchar1 = "Hello World NEW"; //Stores this string in a different addres
        }
    

    以下是整个代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main(int argc, char *argv[]){
        char *pchar1 = "Hello World OLD";
        unsigned long x = (unsigned long)pchar1;
    
        
    
        printf("pchar1 content: %s\n", pchar1);
        printf("Adress of pchar1: %lu\n\n", pchar1);
       
        pchar1 = "Hello World NEW";
        printf("pchar1 content: %s\n", pchar1);
        printf("Adress of pchar1: %lu\n\n", pchar1);
    
        printf("Old addr stores in 'x': %lu\n", x);
        printf("Reading old pchar1 mem addr (from x): %s\n\n", (char *)x);
    
        //Overflow?
        while(1){
            pchar1 = "Hello World OLD"; //Stores this string in a different addres
            pchar1 = "Hello World NEW"; //Stores this string in a different addres
        }
    
        printf("\nSuccess!...\n");
        return 0;
    }
    

    提前感谢!

    2 回复  |  直到 2 年前
        1
  •  1
  •   dbush    2 年前

    字符串常量通常存储在程序内存的静态只读部分。无论是否保留指向这些常量的指针,这些常量在程序的整个生命周期内都是可用的。

    此外,如果一个字符串常量在程序中出现不止一次,那么这些实例中的每一个引用同一块内存的情况并不罕见。

    在这种特殊情况下:

    while(1){
        pchar1 = "Hello World OLD"; //Stores this string in a different addres
        pchar1 = "Hello World NEW"; //Stores this string in a different addres
    }
    

    在该只读内存段中存储了两个字符串常量。在循环的每次迭代中 pchar1 被修改为指向其中一个字符串常量。因此,它并没有创建更多正在使用的内存。

    另一方面,如果你有这样的东西:

    void foo(void)
    {
        char s[] = "Some very very very long string";
        foo();
    }
    

    然后你打电话 foo ,堆栈上会有一个数组,用于存储字符串 "Some very very very long string" 对于函数的每次迭代一次,最终您将耗尽堆栈空间,并且 s 发生得越快。

        2
  •  1
  •   yano    2 年前

    @dbush的回答非常好,只是一个快速的插件,希望能让事情变得清楚。这基本上就是你正在做的事情

    // In read-only memory. Just making these addresses up obviously.
    // I don't know if they'd be more likely to be consecutively
    // addressed or aligned in some way
    0x100: "Hello World OLD"
    0x200: "Hello World NEW"
    

    现在进入您的循环

    // first iteration
    pchar1 = "Hello World OLD";  // ==> now pchar1 == 0x100
    pchar1 = "Hello World NEW";  // ==> now pchar1 == 0x200
    
    // second iteration
    pchar1 = "Hello World OLD";  // ==> now pchar1 == 0x100
    pchar1 = "Hello World NEW";  // ==> now pchar1 == 0x200
    

    并且永远, pchar1 只是不断被字符串文字地址覆盖。


    在评论中回答您的新问题(如果我在下面):

    这取决于情况。如果你有一个无限循环 分配 每次迭代的内存(使用 malloc )或者类似的,而你从来没有 free 是的,你会有失控的内存消耗,最终耗尽:

    #include <string.h>
    ...
    // very simplified view
    while(1)
    {
       // alloctes 50 bytes
       pchar1 = malloc(50);
       // doesn't have to be a random string, "Hello World NEXT"
       // is still a string literal, lets say at address 0x300, but
       // each time you malloc it returns a _new_ pointer to _new_
       // memory. This new memory address is stored in pchar1. strcpy
       // _copies_ the string literal at address 0x300 into the new
       // memory pointed to by pchar1.
       strcpy(pchar1, "Hello World NEXT");
       // use pchar1
       // ...
       // WHOOPS, forgot to free. When you loop back around,
       // the previous value of pchar1 will be replaced with the
       // new value from malloc, but the previously allocated memory
       // will still be allocated. When you lose that previous pointer/
       // don't free it, that's called a memory leak. This loop will
       // allocate memory indefinitely until you run out.
    }
    

    在C语言中,您必须手动管理内存,这通常意味着您必须 自由的 每次 malloc ( but there's a debate about that depending on the situation )

    // this is fine. Not best practice, but free of leaks
    // and unbound memory allocation
    while(1)
    {
       pchar1 = malloc(50);
       // use pchar1 however
       free(pchar1);
    }
    

    或者,您可以完全避免动态分配内存:

    while(1)
    {
       // here, pchar1 is allocated in _automatic storage_ (on the stack
       // in every C implementation I've ever used). Here, the program
       // "deallocates" pchar1 when the closing } is hit
       char pchar1[50];
       // the string literal is still at 0x300, we're just copying its
       // data into the pchar1 memory (different address than 0x300)
       strcpy(pchar1, "Hello World NEXT");
       // use pchar1
       // ...
       // ok, as soon as we hit this closing brace } pchar1 is
       // deallocated ... and reallocated new when we loop back
       // around
    }