[英]does incrementing pointer happens on contiguous memory in C
我正在為分配增加指針變量,但它給了我段錯誤消息。 程序沒有任何問題,因為我的程序一直執行到結束,除了 return 語句。 所以基本上我在想
當我們像pointer+1
這樣遞增指針時,我們在連續的 memory 和 function 內部向前移動 - 可能在現實中 - 變量和 function 的地址的地址 - 如果我以分散的方式調用錯誤,則可能是正確的。 And when we increment pointer to move into next contiguous memory address and that memory could be anything (some other function/program) and my allocation is done on some area that serves memory for something else and may be something outside the memory region of abc
function . 這是我的代碼
#include <stdio.h>
struct abc{ char *c;};
void abc(struct abc **t1);
int main() {
struct abc *k;
abc(&k);
printf("%s\n",k->c);
// printf("%s\n",k->c);
printf("%s\n",(k+1)->c);
// printf("%s\n",(k+2)->c);
return 1;
}
void abc(struct abc **t1){
*t1=(struct abc *)malloc(sizeof(struct abc ));
(*t1)->c="hello";
*(t1+1)=(struct abc *) malloc((sizeof(struct abc )));
(*t1+1)->c="cool";
*(t1+2)=(struct abc *) malloc((sizeof (struct abc )));
//(*t1+2)->c="Super cool";
}
還有一個問題是為什么我在main
function 的返回時似乎出現了段錯誤。 因為主 memory 區域不同於abc
memory 區域。 我需要對此進行一些解釋,並且有關這種分配方式是否錯誤的問題。 如果它沒有錯,如何糾正以使其在沒有段錯誤的情況下工作
更新
#include <stdio.h>
struct abc{ char *c;};
void abc(struct abc **t1);
void abc2(struct abc *t1);
int main() {
struct abc *k;
abc(&k);
//printf("%s\n",k->c);
// k->c="hi"; Seg Fault causes because ->c is immutable from assigning string literal
// printf("%s\n",k->c);
printf("%s\n",(k)->c);
printf("%s\n",(k+1)->c);
printf("%s\n",(k+2)->c);
// / printf("%s\n",(k+2)->c);
return 1;
}
void abc(struct abc **t1){
*t1=(struct abc *)malloc(sizeof(struct abc)*3);
abc2((*t1));
abc2((*t1+1));
abc2((*t1+2));
}
void abc2(struct abc *t1){
(t1)->c="cool";
}
上面的代碼在沒有 segFault 的情況下工作,但它與答案不同,所以上面的代碼有什么問題
如下也有效
#include <stdio.h>
struct abc{ char *c;};
void abc(struct abc **t1);
void abc2(struct abc *t1);
int main() {
struct abc *k;
abc(&k);
//printf("%s\n",k->c);
// k->c="hi"; Seg Fault causes because ->c is immutable from assigning string literal
// printf("%s\n",k->c);
printf("%s\n",(k)->c);
printf("%s\n",(k+1)->c);
printf("%s\n",(k+2)->c);
// / printf("%s\n",(k+2)->c);
return 1;
}
void abc(struct abc **t1){
*t1=(struct abc *)malloc(sizeof(struct abc)*3);
(*t1)->c="Cool";
(*t1+1)->c="more cool";
(*t1+2)->c="super cool";
//below also works
abc2((*t1));
abc2((*t1+1));
abc2((*t1+2));
/* (*t1)->c="hello";
//*(t1+1)=(struct abc *) malloc((sizeof(struct abc)));
(*t1+1)->c="cool";
//*(t1+2)=(struct abc *) malloc((sizeof (struct abc)));
(*t1+2)->c="Super cool";*/
}
void abc2(struct abc *t1){
(t1)->c="cool";
}
您傳遞給 abc() 的值指向未初始化的 memory。 您必須為要存儲的三個結構提供malloc
空間。 否則,取消引用它是未定義的行為。 在我看來,您的目標是讓k
成為一個由 3 個指向結構的指針組成的數組。 如果是這種情況,您應該像這樣聲明它:
struct abc **k = (struct abc **)malloc(sizeof(struct abc *) * 3);
這應該在 32 位系統上分配 12 個字節(每個指針 4 個),或在 64 位系統上分配 24 個字節(每個指針 8 個)。
由於k
現在是一個指向指針的指針而不僅僅是一個指針,所以在調用 abc() 時不再需要獲取它的地址,因此下一行變為:
abc(k);
在 abc function 內部,您不應手動將值遞增到指針。 這就是[]
運算符的目的。 您還應該手動將字符串轉換為char*
s。 進行這些更改后,您的 abc function 應如下所示:
void abc(struct abc **t1){
t1[0]=(struct abc *)malloc(sizeof(struct abc));
t1[0]->c=(char *) "hello";
t1[1]=(struct abc *)malloc(sizeof(struct abc));
t1[1]->c=(char *) "cool";
t1[2]=(struct abc *)malloc(sizeof(struct abc));
t1[2]->c=(char *) "Super cool";
}
注意t1[0]
和*t1
如何做同樣的事情。 后者應始終與 arrays 一起使用,以明確t1
實際上是一個數組。
您應該在 printf() 調用中進行類似的更改,使它們看起來像這樣:
printf("%s\n",k[0]->c);
printf("%s\n",k[1]->c);
printf("%s\n",k[2]->c);
最后,您應該始終釋放 malloc 的 memory:首先釋放數組中的每個指針:
free(k[0]);
free(k[1]);
free(k[2]);
然后釋放數組本身:
free(k);
養成始終釋放數據的習慣將非常有助於防止大型程序中出現痛苦的 memory 錯誤。
畢竟,您的最終程序應該如下所示:
#include <stdio.h>
struct abc {
char *c;
};
void abc(struct abc **t1);
int main() {
struct abc **k = (struct abc **)malloc(sizeof(struct abc *) * 3);
abc(k);
printf("%s\n",k[0]->c);
printf("%s\n",k[1]->c);
printf("%s\n",k[2]->c);
free(k[0]);
free(k[1]);
free(k[2]);
free(k);
return 1;
}
void abc(struct abc **t1){
t1[0]=(struct abc *)malloc(sizeof(struct abc));
t1[0]->c=(char *) "hello";
t1[1]=(struct abc *)malloc(sizeof(struct abc));
t1[1]->c=(char *) "cool";
t1[2]=(struct abc *)malloc(sizeof(struct abc));
t1[2]->c=(char *) "Super cool";
}
要回答您的最后一個問題,段錯誤的行為和時間可能是一件非常棘手且不可預測的事情。 它們通常是由未定義的行為引起的,在同一程序的不同執行之間甚至可能不一樣。 您應該知道的是,程序中發生段錯誤的位置與發生段錯誤的memory中的位置無關。
分配方法是正確的,但是您忘記了初始化k
,所以k
是一個懸空指針。 這就是您有分段錯誤的原因。 我通過添加一個編譯器將初始化的變量來應用一個簡單的“臟”修復,只是為了證明這是問題所在。
#include <stdio.h>
#include <stdlib.h>
struct abc{ char *c;};
void abc(struct abc **t1);
int main() {
struct abc _abc[2], *k;
k = &_abc[0];
abc(&k);
printf("%s\n",k->c);
printf("%s\n",k->c);
printf("%s\n",(k+1)->c);
//printf("%s\n",(k+2)->c);
return 1;
}
void abc(struct abc **t1){
*t1=(struct abc *)malloc(sizeof(struct abc ));
(*t1)->c=malloc(50);
sprintf((*t1)->c, "hello");
*(t1+1)=(struct abc *) malloc((sizeof(struct abc )));
(*t1+1)->c=malloc(50);
sprintf((*t1+1)->c, "cool");
*(t1+2)=(struct abc *) malloc((sizeof (struct abc )));
//(*t1+2)->c="Super cool";
}
編譯后
~$ gcc memtest.c -o memtest
~$ ./memtest
hello
hello
cool
要了解為什么您在main
而不是abc
中出現分段錯誤,您需要在匯編程序gcc test.c -S -ggdb3
中轉換示例。 在我的例子中,在 ARM64 上, k
被優化了。 在調用abc()
之前,編譯器會插入一個__stack_chk_guard
。 這是匯編中的段(ARM64)
.arch armv8-a
.file "memtest_bug.c"
.text
.Ltext0:
.align 2
.global main
.type main, %function
main:
.LFB6:
.file 1 "memtest_bug.c"
.loc 1 8 16
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
mov x29, sp
.loc 1 8 16
adrp x0, :got:__stack_chk_guard
ldr x0, [x0, #:got_lo12:__stack_chk_guard]
ldr x1, [x0]
str x1, [sp, 24]
mov x1,0
.loc 1 10 9
add x0, sp, 16
bl abc
當調用abc()
時, k
指向一個屬於進程的 memory 區域,所以它仍然是一個有效的段,不會產生分段錯誤。 當 main 完成時,編譯器插入一個代碼來檢查堆棧保護,如果檢查失敗,它會調用__stack_chk_fail
。
mov x3, 0
beq .L3
bl __stack_chk_fail
.L3:
mov w0, w1
ldp x29, x30, [sp], 32
.cfi_restore 30
.cfi_restore 29
.cfi_def_cfa_offset 0
ret
.cfi_endproc
此代碼檢測 memory 保護的故障並生成分段故障。 這是生成故障時的堆棧(在 ARM64 上)
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x0000fffff7e7cd68 in __GI_abort () at abort.c:79
#2 0x0000fffff7eca29c in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0xfffff7f89f58 "*** %s ***: terminated\n") at ../sysdeps/posix/libc_fatal.c:155
#3 0x0000fffff7f3c600 in __GI___fortify_fail (msg=msg@entry=0xfffff7f89f40 "stack smashing detected") at fortify_fail.c:26
#4 0x0000fffff7f3c5d4 in __stack_chk_fail () at stack_chk_fail.c:24
#5 0x0000aaaaaaaaa8e4 in main () at memtest_bug.c:18
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.