использование malloc () для двойных указателей - PullRequest
2 голосов
/ 23 октября 2010

вопрос malloc.

Сначала я генерирую несколько строк.

И, во-вторых, я выделяю пробел для копирования указателей, которые указывают на эти строки. В этот момент программа, вероятно, должна аварийно завершить работу, поскольку я пытался скопировать эти указатели в никуда, но это не приводит к сбою. Как это возможно?

Любые комментарии приветствуются.

#include <stdio.h>

int main(int argc, char *argv[])
{
    int         i,
                iJ,
                iCharCount  = 0,
                iCharVal,
                iStrLen = 0,
                iStrNum = 50,
                iStrCount = 0,
                iAllocSize = 0;
    char       *pcStr,
               *pcStr_CurPos,
             **ppcStr,
             **ppcStr_CurPos;

    // suppose, an average length of string is * N bytes.
    iAllocSize  = iStrNum * 6;
    iStrCount = 0;

    // allocate ...
    pcStr = pcStr_CurPos = (char*) malloc (iAllocSize);

    if (pcStr==NULL){printf("NULL == malloc()\n"); exit (1);}

    for (i=0; i < iStrNum; i++)
    {
        iStrCount++;
        iStrLen = rand() % 7 + 2; // is in the range 2 to 8
            printf("Len of Str=%d; str=[", iStrLen);
        for (iJ = 0; iJ < iStrLen-1; iJ++)
        {
            // A-Z a-z
            iCharVal = rand() % 58 + 65;

            if (iCharVal >  90 && iCharVal < 97) {iJ--; continue;}

            if (pcStr_CurPos < pcStr + iAllocSize )
            {
                    printf ("%c", iCharVal);
                *pcStr_CurPos++ = iCharVal;
                iCharCount ++;
            }
            else
            {
                *pcStr_CurPos++ = 0;
                iCharCount ++;
                    printf ("]\n");
                goto exit;
            }

        }
            printf ("]\n");
        *pcStr_CurPos++ = 0;
        iCharCount ++;
    }
exit:

    // I allocate NOTHING, ...
    ppcStr = ppcStr_CurPos = (char**) malloc (0); // ZERO !

    // Copying pointers ...
    pcStr_CurPos = pcStr;
    while(pcStr_CurPos < pcStr + iCharCount)
    {
        //... BUT IT WORKS AND DON'T CRASH.
        // HOW IS IT POSSIBLE ???
        *ppcStr_CurPos++ = pcStr_CurPos;
        while (*pcStr_CurPos++) ;
    }

    ppcStr_CurPos = ppcStr;
    iStrNum = iStrCount;

    printf ("\n Output ppcStr:\n", iCharCount );

    while(iStrNum--)
    {
        printf("[%d][%s]\n", iStrNum, *(ppcStr_CurPos++));
    }

    printf ("Press Enter key or sth\n");
    getchar();
    return 0;
}

Ответы [ 2 ]

9 голосов
/ 23 октября 2010

В общем случае C не гарантированно аварийно завершает работу, если вы обращаетесь к неинициализированной памяти.Поведение не определено, что означает, что все может случиться.Как говорится, компилятор может заставить демонов вылететь из вашего носа.

1 голос
/ 23 октября 2010

Я считаю, что на практике система может выделить больше памяти, чем вы запрашивали. Так вот

ppcStr = ppcStr_CurPos = (char**) malloc (0); // ZERO !

фактический размер блока может быть 1 или более :

Если размер запрошенного пространства равен нулю, поведение определяется реализацией: либо возвращается нулевой указатель, либо поведение такое, как если бы размер был некоторым ненулевым значением, за исключением того, что возвращенный указатель не должен использоваться для получить доступ к объекту.

Таким образом, если возвращаемый указатель не равен нулю, он может указывать на буфер ненулевой длины.

Тогда вот

pcStr_CurPos = pcStr;
while(pcStr_CurPos < pcStr + iCharCount)
{
    //... BUT IT WORKS AND DON'T CRASH.
    // HOW IS IT POSSIBLE ???
    *ppcStr_CurPos++ = pcStr_CurPos;
    while (*pcStr_CurPos++) ;
}

после копирования 1-го байта в буфер "0 байт" во внутреннем while вы, кажется, проходите pcStr_CurPos до конца строки, на которую он указывает, и, следовательно, выходите из внешнего цикла. Таким образом, больше никаких байтов не копируется!

Так что я бы рискнул сказать, что на практике вы не обязательно пишете в нераспределенную память (хотя согласно приведенной выше цитате запись в этот буфер все еще не определена, но, как справедливо указала @novalis, неопределенное поведение может не обязательно приводит к сбою).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...