关于C指针的困惑

huangapple go评论65阅读模式
英文:

Confusion about C pointers

问题

我发送这条消息来解决我无法管理和处理的困惑。

foo1函数的代码应该可以工作。我为您提供了代码详细信息。

当我运行代码时,在第12行出现分段错误。然后我在foo2中以不同的语法符号进行了小改变。foo2可以工作。但我想更深入地了解指针的工作原理。哪种错误可能会导致这个错误。如果我不使用第12行,一切看起来都很正常。这个问题的主要原因是什么。您能帮助我吗?

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

int foo1(char ***BufferArray, char *item, int idx);
int foo2(char ***BufferArray, char *item, int idx);

int main() {
    char **ptr = malloc(sizeof(char *) * 3);
    char a[] = "hello0";
    char b[] = "hello1";
    char c[] = "hello2";
    foo1(&ptr, a, 0);
    // foo1(&ptr, b, 1); // 异常发生。分段错误 // 第12行
    printf("[%s]", *(ptr + 0));
    printf("[%s]", *(ptr + 1));
    getchar();
    return 0;
}

int foo1(char ***BufferArray, char *item, int idx) {
    int n;
    n = 1;
    **(BufferArray + idx) = malloc(sizeof(char) * strlen(item));
    strcpy(**(BufferArray + idx), item);
    return 0;
}

int foo2(char ***BufferArray, char *item, int idx) {
    int n;
    char **temp = *BufferArray;
    *(temp + idx) = malloc(sizeof(char) * strlen(item));
    strcpy(*(temp + idx), item);
    *BufferArray = temp;
    return 0;
}
英文:

I am sending this message to clear my confusion that I could not manage and handle.

The foo1 function code should work. I am giving the code details for you.

When I run the code, the result is a segmentation error at line 12. Then I made a little change in foo2 in different syntax notation. foo2 is working. But I want to learn more deeply how pointers work. Which kind of error can cause this error. If I don't use line 12 everything looks fine. What would be the main reason for this issue. Could you please assist me?

#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;
#include&lt;string.h&gt;
int foo1(char ***BufferArray,char *item,int idx);
int foo2(char ***BufferArray,char *item,int idx);
int main(){
    char **ptr=malloc(sizeof(char*)*3);
    char a[]=&quot;hello0&quot;;
    char b[]=&quot;hello1&quot;;
    char c[]=&quot;hello2&quot;;
    foo1(&amp;ptr,a,0);
    //foo1(&amp;ptr,b,1);//Exception has occurred. Segmentation fault //line 12
    printf(&quot;[%s]&quot;,*(ptr+0));
    printf(&quot;[%s]&quot;,*(ptr+1));
    getchar();
    return(0);
}

int foo1(char ***BufferArray,char *item,int idx){
    int n;
    n=1;
    **(BufferArray+idx)=malloc(sizeof(char)*strlen(item));
    strcpy(**(BufferArray+idx),item);
    return(0);
}

int foo2(char ***BufferArray,char *item,int idx){
    int n;
    char **temp=*BufferArray;
    *(temp+idx)=malloc(sizeof(char)*strlen(item));
    strcpy(*(temp+idx),item);
    *BufferArray=temp;
    return(0);
}

答案1

得分: 2

您正在将指向函数 foo1 的指针传递给它:

foo1(&amp;ptr,b,1);

其中 ptr 是如下定义的指向指针的指针:

char **ptr = malloc(sizeof(char*) * 3);

因此,在函数内部访问指针时,您可以使用以下任一表达式:*BufferArray*(BufferArray + 0)BufferArray[0]

在函数 foo2 中,实际上使用了其中一个表达式:

char **temp = *BufferArray;

在函数 foo1 中使用像 *(BufferArray+idx) 这样的表达式,其中变量 idx 大于 0 会尝试访问传递的指针之外的内存,这会在进一步解引用该表达式时引发未定义的行为。

请注意,字符串包含结尾的零字符 '\0'。如果您要将字符串复制到分配的内存中,还需要为它保留内存。例如,您需要这样写:

*(temp+idx) = malloc(sizeof(char) * (strlen(item) + 1));
strcpy(*(temp+idx), item);

malloc 的调用中使用 sizeof(char) 是多余的,会使代码不够可读。相反,您可以简单地写成:

*(temp+idx) = malloc(strlen(item) + 1);
英文:

You are passing to the function foo1

foo1(&amp;ptr,b,1);

a pointer to the pointer ptr defined like

char **ptr=malloc(sizeof(char*)*3);

So to access the pointer within the function you may use an expression either like *BufferArray or like *( BufferArray + 0 ) or like BufferArray[0].

In the function foo2 you are in fact using one of these expressions

char **temp=*BufferArray;

An expression like that *(BufferArray+idx) used in the function foo1 where the variable idx is greater than 0 tries to access memory outside the passed pointer that invokes undefined behavior when the expression is further dereferenced.

Pay attention to that strings contain trailing zero character &#39;\0&#39;. You need to reserve memory also to it if you are going to copy a string in the allocated memory. That is you need to write for example

*(temp+idx)=malloc(sizeof(char)*strlen(item) + 1);
                                             ^^^                  
strcpy(*(temp+idx),item);

Using sizeof( char ) in the call of malloc is redundant and makes the line kess readable. Instead you could write simply

*(temp+idx)=malloc( strlen(item) + 1 );

答案2

得分: 1

foo1()中的主要问题是没有考虑运算符优先级。**(BufferArray+idx) 应该是 *(*BufferArray)+idx)。这也可以写成 *(BufferArray[0]+idx)(*BufferArray)[idx]BufferArray[0][idx]

原始的 **(BufferArray+idx) 等价于 *BufferArray[idx](即 *(BufferArray[idx]))或 BufferArray[idx][0]。在调用 foo1(&amp;ptr,b,1) 时,BufferArray 指向 main() 中的 char **ptr 变量,而 idx 是 1。BufferArray+idx 指向了刚刚超过 ptr 变量末尾的位置。指针值是有效的,因为允许指向变量末尾刚刚超过的位置,但是对该指针进行解引用会导致未定义行为(UB),就像访问数组末尾刚刚超过的元素一样会导致UB。


正如其他人指出的,调用 *(temp+idx)=malloc(sizeof(char)*strlen(item)); 没有分配足够的空间来存储字符串末尾的空字符,因此随后的调用 strcpy(*(temp+idx),item); 会写入已分配内存的末尾(strcpy(a,b) 复制 strlen(b)+1 个字符,包括空字符),导致UB。

英文:

The main problem in foo1() is lack of consideration of operator precedence. **(BufferArray+idx) should be *(*BufferArray)+idx). This could also be written *(BufferArray[0]+idx) or (*BufferArray)[idx] or BufferArray[0][idx].

The original **(BufferArray+idx) is equivalent to *BufferArray[idx] (i.e. *(BufferArray[idx])) or BufferArray[idx][0]. In the call foo1(&amp;ptr,b,1), BufferArray points to the char **ptr variable in main() and idx is 1. BufferArray+idx points to the location just past the end of the ptr variable itself. The pointer value is valid because pointing just past the end of a variable is allowed, but dereferencing that pointer results in undefined behavior (UB) in the same way that accessing an element just past the end of an array results in UB.


As pointed out by others, the call *(temp+idx)=malloc(sizeof(char)*strlen(item)); does not allocate room to store a null terminator character at the end of the string, so the subsequent call strcpy(*(temp+idx),item); writes past the end of the allocated memory (strcpy(a,b) copies strlen(b)+1 characters, including the null terminator character), resulting in UB.

huangapple
  • 本文由 发表于 2023年7月13日 21:17:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76679805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定