迭代地迭代字符串数组(指针值似乎被“卡住”)

时间:2018-12-18 09:42:09

标签: c arrays pointers scope iteration

编辑: 我意识到OP中的代码很长且很难阅读。我用4行代码强调了这个问题。

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

我想在整个字符串数组中递增而不丢失指向第一个字符的指针。因此,我初始化一个新的指针“ a”以指向第一个字符。但是,当我增加'a'指针后,似乎改变了't'指向的内容!在printf语句中,我希望t的指针值保持不变,但是它似乎以'a'递增,现在指向第二个字符。为什么会这样呢?

已解决: 在上面的示例中,a和t似乎是相同的指针,因此,如果我更改一个(例如通过递增),则更改也将反映在pther中。但是,如果我将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的字符串。 / p>

本质上,该函数的作用是为字符串指针和数组指针创建本地指针值。然后,它从array2中提取第一个字符串,并开始遍历它以查找与输入字符串的第一个字母匹配的对象。如果找不到匹配项,则该函数将继续到下一个字符串,直到找到完全匹配项或遍历整个array2。然后,它返回到其调用环境。

我遇到了一些意外行为。当我调用函数(具有相同的参数)时,在调用完该函数之后,数组指针似乎指向上次调用中保留的确切位置。

例如,如果我调用compString("arp", array2, 5),则该函数将标记aharp开始的匹配项。

然后,如果我调用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 :(得分:1)

您的循环导致偏离1个错误。您想要做的是遍历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]);

因此,当i4时,将其增加到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"};

此外,我不知道您是否必须实现此功能,因为已经完成了这项任务,但是如果您只想查找子字符串,则无需将轮子重新发明为{{3 }}已经做到了。

答案 1 :(得分:0)

您是否正在寻找这样的东西:

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 wihch终止了字符串指针数组-因此您无需提供arrays /的大小。

答案 2 :(得分:0)

正如评论中提到的那样,您注意到的副作用是由于此行*++(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定义的子字符串进行比较。您需要确保p1p2都不会超出其各自字符串的结尾,并且它们指向相同的字符。

        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++)