Работа с длинами и позициями

В программировании мы часто имеем понятие как об относительной «длине» чего-либо, так и о его абсолютном «положении» в некотором окружении. Когда мы сравниваем два элемента, они должны быть либо относительными, либо абсолютными.

Вот несколько примеров из двух:

ДоменРодственникАбсолют
времяпродолжительностьсвидание
указателииндексуказатель
массивыдлинадолжность

(чтобы убедиться, что указатели и массивы тесно связаны)

Относительный элемент может быть преобразован в абсолют путем сложения, и для этого требуется абсолют, заданный в качестве базовой линии:

absolute2 = absolute1 + relative;  // or relative + absolute

Продолжительность можно преобразовать в дату, добавив базовую дату.

 date = 1 /*day*/ + Today; // Tomorrow..

Индекс можно преобразовать в указатель, добавив базовый указатель.

char *p ...;
int i ...;
char *q = p + i; // or i + p;

Длину можно преобразовать в позицию, добавив некоторую базовую позицию.

int startPosition ... ;
int length ...;
int onePastTheEndPosition = startPosition + length; // or length + startPosition;    

Абсолютные элементы можно преобразовать в относительные путем вычитания, и для этого требуется два абсолютных элемента:

int startPosition ... ;
int endPosition ... ;
int length = endPostion - startPosition;

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

Давайте посмотрим на этот цикл, где управляющая переменная цикла проходит длину некоторого элемента, который должен быть расположен где-то внутри массива. (Такой цикл может искать слово в строке, помещая его во внешний цикл, который продвигается вперед. startPosition):

for ( i = 0; i < length; i++ ) 
    a [ startPosition + i ] ...

Потому что a[0] относится к абсолютному первому элементу, массивы должны быть проиндексированы по абсолютной позиции, здесь мы конвертируем i от элемента относительной длины до абсолютной позиции в массиве для индексации.

В качестве альтернативы мы можем вычислить положение непосредственно в переменной управления циклом.

for ( i = startPosition; i < startPosition + length; i++ )
     a [ i ] ...

Здесь i — это позиция с уже добавленной базовой позицией. Добавляя базовую линию во время инициализации цикла, мы также должны использовать абсолютную позицию во время условного управления циклом. (Как и в предыдущем случае, этот цикл можно использовать для поиска слова в строке, заключая его во внешний цикл, продвигающий startPosition.)

Когда мы пишем простые циклы for:

for ( int i = 0; i < N; i++ ) ...

Похоже, что мы не можем на самом деле сказать, является ли переменная управления циклом длиной или позицией, но на самом деле это и то, и другое, потому что, если бы мы использовали здесь базовую абсолютную позицию, она была бы равна нулю. Таким образом, поскольку 0+0 равно нулю, а N+0 равно N, эта управляющая переменная цикла обладает свойствами как относительной длины, так и абсолютного положения.


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

char *textToSearch = "hello world";
char *toMatch = "world";
int N = strlen(textToSearch);
int M = strlen(toMatch);

for ( int startPosition = 0; startPosition < N; startPosition++ ) {
    int i; // declared outside the for so we can use it after
    for ( i = 0; i < M; i++ ) {
        if ( textToSearch [ startPosition + i ] != toMatch [ i ] )
            break; // stop the inner loop and move on to outer loop
    }
    if ( i == M ) {
        printf ("match found at %d\n", startPosition );
        // we might stop the outer loop if we're only looking for the first ocurrence
    } else {
        printf ("match not found at %d\n", startPosition );
    }
}

Заметим, что управляющая переменная внутреннего цикла, iявляется позицией в двух случаях: textToSearch [ startPosition + i ] идентифицирует символ в следующей позиции, чтобы начать поиск в большей строке, в то время как toMatch [ i ] идентифицирует символ в следующей позиции в слове для сравнения.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *