Итеративная итерация массива строк (значение указателя, похоже, «застряло») - PullRequest
0 голосов
/ 18 декабря 2018

РЕДАКТИРОВАТЬ: я понимаю, что код в моем OP является длинным и трудно читаемым.Я выдвинул на первый план проблему с 4 строками кода.

char **t = {"Hello", "World"};
char **a = t;
++(a[0]);
printf("%c\n",**t);

Я хочу увеличивать массив строк без потери указателя на первый символ.Поэтому я инициализирую новый указатель «а», чтобы он указывал на первый символ.Однако после того, как я увеличу указатель 'a', он, похоже, изменит то, на что указывает 't'!В выражении printf я ожидаю, что значение указателя t останется неизменным, но, похоже, оно увеличивается с «a» и теперь указывает на второй символ.Почему это происходит?

ИСПРАВЛЕНО: В приведенном выше примере a и t кажутся одним и тем же указателем, поэтому, если я изменяю один (например, увеличивая), изменение также отражается в другом.Однако, если я разыменую t в другую переменную, то я могу изменить указанную переменную без отражения этого изменения в t.В приведенном выше примере это выглядит так:

char *a = t[0];
++a;
printf("a value: %c\n", *a);
printf("t value: %c\n", **t);

Я думаю, что я изначально был сбит с толку по поводу разыменования, поскольку t указывает на указатель.Каждый полученный ответ заключается в использовании индексации массива, а не указателей, и я понимаю, почему.

ОРИГИНАЛЬНАЯ ПОЧТА: скажем, у меня есть:

array1 {"arp", "live", "strong"}, and 
array2 {"lively", "alive", "harp", "sharp", "armstrong"}

Я пытаюсь найтистроки в array1, которые являются подстроками любой строки в array2.

. Для этого я написал вспомогательную функцию (compString), которая принимает строку из array1, всего array2 и длиной array2.

По сути, функция создает локальные значения указателя как для указателя строки, так и для указателя массива.Затем он извлекает первую строку из array2 и начинает проходить по ней, чтобы найти соответствие для первой буквы входной строки.Если совпадения не найдено, функция переходит к следующей строке, пока не будет найдено полное совпадение или пока не пройдёт все array2.Затем он возвращается в свою среду вызова.

Я столкнулся с неожиданным поведением.Когда я вызываю функцию (с теми же аргументами), после того, как она уже была вызвана, указатель массива точно указывает на то место, где она остановилась в предыдущем вызове.

Например, если я вызываю compString("arp", array2, 5)тогда функция помечает совпадение, начиная с a в harp.

Затем, если я вызываю compString("live", array2, 5), функция начинается с a в harp и продолжается до концамассива без пометки совпадения.

Наконец, когда я вызываю compString("strong", array2, 5), array2 теперь указывает на мусор, так как он уже был повторен, и не помечает совпадение.

Поскольку одна из первых функций вспомогательной функции заключается в «локализации» передаваемых указателей (то есть, создать локальную переменную-указатель и присвоить ей значение указателя, передаваемого в функцию, а затем выполнить итерацию этой локальной переменной)Я бы предположил, что последующие вызовы функции не «сохранят» предыдущее значение указателя.Есть указатели?

Источник приложен:

#include <stdio.h>
#include <string.h>

int compString(char *, char **, int);

int main(void)
{
    int sz1 = 3;
    int sz2 = 5;
    char *p, *p2;
    char *array1[] = {"arp\0", "live\0", "strong\0"};
    char *array2[] = {"lively\0", "alive\0", "harp\0", "sharp\0", "armstrong\0"};

    compString("arp\0",array2,5);
    compString("live\0",array2,5);
    compString("strong\0",array2,5);
}

int compString(char *arr1, char **arr2, int sz2)
{
    printf("\n\n\n");
    printf("WORD: %s\n",arr1);
    int i = 0;
    char *a1 = arr1;
    char **a2 = arr2;
    char *p;
    char *p2;

    printf("BEGIN ITERATION %d\n",i);
    printf("Checking against word: %s\n",a2[i]);
    while (i < sz2)
    {
        printf("%c\n",*a2[i]);
        if (*a1 == *a2[i])
        {
            char *p = a1;
            char *p2 = a2[i];

            while ((*p == *p2) && (*p != '\0'))
            {
                ++p;
                ++p2;
            } 

            if (*p == '\0')
            {
                return 1;
            }

            else
            {
                *++(a2[i]);
                if (*(a2[i]) == '\0')
                {
                    ++i;
                    printf("BEGIN ITERATION %d\n",i);
                    printf("Checking against word: %s\n",a2[i]);
                }
            }
        }

        else 
        {
            *++(a2[i]);
            if (*(a2[i]) == '\0')
            {
                ++i;
                printf("BEGIN ITERATION %d\n",i);
                printf("Checking against word: %s\n",a2[i]);
            }
        }
    }
    return 0;
}

sample output

Ответы [ 3 ]

0 голосов
/ 18 декабря 2018

вы ищете что-то вроде этого:

char *array1[] = {"arp", "live", "strong", NULL};
char *array2[] = {"lively", "alive", "harp", "sharp", "armstrong", NULL};

void findsrings(char **neadles, char **haystack)
{
    while(*neadles)
    {
        char **hay = haystack;
        size_t pos = 0;

        printf("Searching for %s\n", *neadles);
        while(*hay)
        {
            if(strstr(*hay, *neadles))
            {
                printf("Found!! Haystack word is: %s at index %zu in haystack\n", *hay, pos);
            }
            pos++;
            hay++;
        }
        neadles++;
    }
}

int main()
{
    findsrings(array1, array2);

    return 0;
}

вам не нужно '\ 0' в конце строковых литералов, поскольку они автоматически добавляются компилятором C.Я добавил NULL, который завершает массив строковых указателей - поэтому вам не нужно указывать размеры массивов / .

0 голосов
/ 18 декабря 2018

Как уже упоминалось в комментариях, побочный эффект, который вы заметили, связан с этой строкой *++(a2[i]);, которая изменяет содержимое вашего второго массива.Со временем вы в конечном итоге получите второй массив, в котором нет реальных слов.

Обычно ваш код слишком сложен, и вы используете циклы while, когда циклы for лучше подходят.

Например, внешний цикл будет работать лучше как:

for(i=0;i<sz2;i++)
{
    printf("BEGIN ITERATION %d\n",i);
    printf("Checking against word: %s\n",arr2[i]);

И затем, поскольку вы хотите проверить каждую подстроку в arr2[i], вы можете использовать для этого цикл for...

    for(wordstart=arr2[i];*wordstart!='\0';wordstart2++)
    {

Наконец, у вас есть внутренний цикл, который сравнивает каждый символ arr1 с подстрокой, определенной wordstart.Вам необходимо убедиться, что ни p1, ни p2 не выходят за пределы конца соответствующих строк и не указывают на один и тот же символ.

        for(p1=arr1,p2=wordstart;(*p1!='\0')&&(*p2!='\0')&&(*p1==*p2);p1++,p2++);

После того, как любое из этих 3 условий больше не выполняется, если вы проверяете, что p1 достиг конца строки, вы знаете, что он должен найти подстроку.

        if(*p1=='\0')
        {
            printf("Matched %s\n",arr2[i]);
            return 1;
        }

Результирующая функция выглядит следующим образом:

int compString(char *arr1, char **arr2, int sz2)
{
    printf("\n\n\n");
    printf("WORD: %s\n",arr1);
    int i = 0;
    char *p1;
    char *wordstart;
    char *p2;

    for(i=0;i<sz2;i++)
    {
        printf("BEGIN ITERATION %d\n",i);
        printf("Checking against word: %s\n",arr2[i]);

        for(wordstart=arr2[i];*wordstart!='\0';wordstart++)
        {
            for(p1=arr1,p2=wordstart;(*p1!='\0')&&(*p2!='\0')&&(*p1==*p2);p1++,p2++);
            if(*p1=='\0')
            {
                printf("Matched %s\n",arr2[i]);
                return 1;
            }
        }
    }
    return 0;
}

Следует также отметить, что вам не нужно неявно добавлять \0 в строку.Следующее замечательно.

char *array1[] = {"arp", "live", "strong"};

Вы также можете добавить NULL в качестве последнего элемента в списке строк, чтобы вам не нужно было отслеживать, сколько строк.

char *array2[] = {"lively", "alive", "harp", "sharp", "armstrong"};

, что означает, что внешний цикл может быть упрощен до

for(i=0;arr2[i];i++)
0 голосов
/ 18 декабря 2018

Ваш цикл вызывает ошибку "один за другим".То, что вы хотите сделать, это циклически проходить по вашему массиву из 5 строк, то есть от 0 до 4. Мы можем видеть, что когда вы запускаете все три теста, потому что они так или иначе зависят от результата друг от друга (я тоже не смотрел на логику сравненияочень, это кажется довольно запутанным).

Мы можем повторить поведение только с одним тестом:

compString("test", array2, 5);

Таким образом, 5 должен сказать ему цикл от 0 до 4.В функции сравнения у вас есть это:

int i = 0;
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
while (i < sz2)

Пока все хорошо.i < sz2 является верным, он предположительно переходит от 0 до 4, предполагая, что вы увеличиваете i правильно.

Затем, однако, вы делаете это где-то в конце функции:

++i;
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);

Таким образом, когда i равен 4, вы увеличиваете его до 5, и в этот момент функция должна прекратить циклическое перемещение по массиву, но в этот момент вы делаете ту печать, которая пытается получить доступa2[5], которого не существует.Вот где он вылетает для меня в MSVC.

Мое предложение состоит в том, чтобы вы переделали свою логику цикла в нечто вроде этого:

for (int i = 0; i < sz2, i++){
    printf("BEGIN ITERATION %d\n", i);
    printf("Checking against word: %s\n", a2[i]);
    // do something with a2[i] and don't manually change the value of "i"
}

Кроме того, я бы убрал эту строковую логику, там может бытьбыть ошибкой в ​​этом где-то.Вам не нужны все эти подозрительные вызовы разыменования.Если вы хотите получить доступ к символу x из строки y в a2, тогда a2[y][x] сделает свое дело.Например, если вы хотите найти какую-либо букву, просто выполните:

for (int n = 0; n < strlen(a2[y]), n++){
    if (a2[y][n] == 'a')
        printf("found letter 'a' at position %d\n", n);
}

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

char *array1[] = {"arp\0", "live\0", "strong\0"};

Сделайте это:

char *array1[] = {"arp", "live", "strong"};

Кроме того, я не знаю, нужно ли вам реализовать эту функцию, потому что это задача, которую вам дали, ноесли вы просто хотите найти подстроки, вам не нужно заново изобретать колесо, поскольку strstr уже делает это.

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