指针数组上的指针算术

时间:2013-12-21 01:00:37

标签: c arrays pointers

使用程序将字符串拆分为较小的字符串并删除尾随空格,以便充分了解我脑中的指针。但是,当我尝试对指针数组进行指针运算时,我不断得到一个分段错误(测试并计算出这是发生错误的特定行);这是我的代码:

int enfold(char* to_enfold, long unsigned line_length, char** enfolded) {
    int k;

    long unsigned char_num = strlen(to_enfold);
    if (char_num < line_length) {
        for (k = 0; k <= sizeof(to_enfold); k++)
            enfolded[0][k] = to_enfold[k];

        printf("TOO SHORT\n");

        enfolded[0][k] = '\n';

        return 1;
        }

    else {
        int i = LINE_LENGTH-1;

        while ( to_enfold[i] == ' ' ||
                to_enfold[i] == '\t' ||
                to_enfold[i] == '\n' ||
                i == 0) {
            printf("%d\n", i);
            i--;
        }

        for (k = 0; k <= i; k++)
            enfolded[0][k] = to_enfold[k];

        enfolded[0][k] = '\n';

        return 1 + enfold((to_enfold+LINE_LENGTH), line_length, (enfolded+1));
    }
}

问题在于递归,这会导致使用算法(enfolded + 1)的分段错误,但如果我们使用enfolded覆盖则不会。在指针指针上使用指针算法是否有问题。

1 个答案:

答案 0 :(得分:1)

一个问题是在代码中使用sizeof()

if (char_num < line_length) {
    for (k = 0; k <= sizeof(to_enfold); k++)
        enfolded[0][k] = to_enfold[k];

那应该是strlen(),除非你没有在循环的条件下调用strlen(),并且在任何情况下都应该写入循环:

    strcpy(enfolded[0], to_enfold);

但是,这不是代码中您遇到问题的部分。由于您没有向我们展示如何为enfolded分配内存,因此很难知道您做了什么,但很有可能您没有正确分配内存。您应该不仅预先分配了指针数组,而且还预先分配了每个指针所指向的数组(因为您没有在此代码中分配空间)。或者,您需要在此处分配必要的空间。您还没有告诉此函数数组中有多少指针。因此,精心制作的输入很容易让你写出界限。你需要知道指针数组中有多少空间。

所以,我认为你应该:

  1. 在此功能中分配字符串。
  2. 确保在完成后将它们全部释放。
  3. 确保您知道阵列中可以存储多少个字符串。
  4. 如果您使用的是valgrind系统,请使用它来指导您完成内存分配和发布。


    请阅读有关如何创建SSCCE(Short, Self-Contained, Correct Example)的信息。人们可能没有参与帮助的一个原因是你的代码显然不是SSCCE;没有main()功能。这是一个有效的SSCCE的近似值。我做的主要改变是确保字符串为空终止;我很确定这是你问题的很大一部分。

    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static
    int enfold(char *to_enfold, size_t line_length, char **enfolded)
    {
        size_t k;
    
        size_t char_num = strlen(to_enfold);
        if (char_num < line_length)
        {
            for (k = 0; k <= char_num; k++)
                enfolded[0][k] = to_enfold[k];
            printf("TOO SHORT\n");
            enfolded[0][k] = '\n';
            enfolded[0][k+1] = '\0';
            return 1;
        }
        else
        {
            size_t i = line_length - 1;
    
            while (to_enfold[i] == ' ' ||
                   to_enfold[i] == '\t' ||
                   to_enfold[i] == '\n' ||
                   i == 0)
            {
                printf("%zu\n", i);
                i--;
            }
    
            for (k = 0; k <= i; k++)
                enfolded[0][k] = to_enfold[k];
    
            enfolded[0][k] = '\n';
            enfolded[0][k+1] = '\0';
    
            return 1 + enfold((to_enfold + line_length), line_length, (enfolded + 1));
        }
    }
    
    int main(void)
    {
        enum { SIZE = 100 };
        char *enfolded[SIZE];
    
        for (int i = 0; i < SIZE; i++)
            enfolded[i] = malloc(sizeof(char) * SIZE);
    
        char line[4096];
        while (fgets(line, sizeof(line), stdin) != 0)
        {
            int n = enfold(line, 8, enfolded);
            assert(n < SIZE);
    
            for (int i = 0; i < n; i++)
                printf("%d: <<%s>>\n", i, enfolded[i]);
            printf("Parts: %d\n", n);
        }
    
        for (int i = 0; i < SIZE; i++)
            free(enfolded[i]);
    
        return 0;
    }
    

    示例运行:

    $ ./mem <<< "Hello, how are you today?"
    TOO SHORT
    0: <<Hello, h
    >>
    1: <<ow are y
    >>
    2: <<ou today
    >>
    3: <<?
    >>
    Parts: 4
    $
    

    使用valgrind进行检查可以为代码提供干净的健康状况。但是,你可能需要考虑如果你在字符串中间有30个空格会发生什么(我强烈怀疑你会遇到问题,但我没有证明这一点。)

    在Mac OS X 10.9.1 Mavericks上使用GCC 4.8.2进行编译:

    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror mem.c -o mem
    

    我几乎不会使用不那么严格的编译选项进行编译(除非它需要是C99或者,它会破坏思想,C89代码)。请注意,代码确实使用了一些C99功能,特别是for循环中的变量声明。