Как работает '--p' для (p = & (* L) .elem [(* L) .length-1]; p> = q; - p)? - PullRequest
0 голосов
/ 22 сентября 2019

Я пытаюсь отладить следующий код:

Status ListInsert_Sq(SqLIst *L, int i, LElemType_Sq e)
{
    LElemType_Sq *newbase;
    LElemType_Sq *p, *q;

    if(i<1 || i>(*L).length+1)
        return ERROR;                   
    if((*L).length >= (*L).listsize)
    {
        newbase = (LElemType_Sq*)realloc(LElemType_Sq *)realloc((*L).elem, ((*L).listsiz+LISTINCREMENT)*sizeof(LElemType_Sq));
        if(!newbase)
            exit(OVERFLOW);

        (*L).elem = newbase;
        (*L).listsize += LISTINCREMENT; 
     } 

     q = &(*L).elem[i-1];
     for(p=&(*L).elem[(*L).length-1];p>=q;--p)
        *(p+1) = *p;

    *q = e;
    (*L).length++;

    return OK;
} 

Правильно ли здесь использовать --p?В частности, мне интересно, будет ли последний элемент списка перемещен или перезаписан предыдущим элементом?

Спасибо!

Ответы [ 2 ]

1 голос
/ 22 сентября 2019

После перезаписи угаданное намерение кода выглядит следующим образом:


#include <stdlib.h>
#include <string.h>
#include "listmeuk.h"

Status ListInsert_Sq(SqLIst *lp, int index, LElemType_Sq elem)
{
    if(index<1 || index>lp->length+1) return ERROR; // this assumes 1-based indexing
    index--; // transform to zero-based indexing

    if(lp->length >= lp->listsize)
    {
        LElemType_Sq *newbase;
        newbase = realloc(lp->elem, (lp->listsiz+LISTINCREMENT) *sizeof *newbase);
        if(!newbase) exit(OVERFLOW);

        lp->elem = newbase;
        lp->listsize += LISTINCREMENT; 
     } 

    if(index < lp->length) memmove(&(lp->elem[index+1]), &(lp->elem[index]), (lp->length-index) * sizeof lp->elem[0] );

    lp->elem[index] = elem;
    lp->length++;

    return OK; 

} 
1 голос
/ 22 сентября 2019

Этот код (в котором я добавил пропущенную точку с запятой):

for(p=&(*L).elem[(*L).length-1];p>=q;--p)
    *(p+1) = *p;

устанавливает p для указания на последний назначенный элемент в массиве elem.Затем *(p+1) = *p; копирует этот последний элемент набора во вновь выделенное пространство (выделенное с realloc) выше.(Под «назначенным элементом» я подразумеваю тот, для которого было назначено значение.)

Затем --p уменьшает указатель, чтобы указать на предыдущий элемент.(Использование арифметики для указателей работает в единицах элементов массива.) Затем *(p+1) = *p; копирует второй с последнего назначенный элемент в предыдущее пространство последнего назначенного элемента.Затем цикл продолжается в этом направлении, эффективно перемещая каждый элемент на один шаг вверх по массиву.

В конечном счете, цикл, по-видимому, предназначен для остановки, когда элемент с индексом i-1 был перемещен, как q устанавливается на адрес этого элемента с q = &(*L).elem[i-1];.

Однако он неисправен.Если i равен единице, то q указывает на первый элемент массива, и p в конечном итоге достигнет этого элемента, а --p попытается уменьшить значение p до точки начала массива.Поведение этой попытки не определено стандартом C.(Предполагается, что L указывает на начало массива. Возможно L указывает на массив после его начала, и в этом случае эта проблема не возникает.)

...