所以我在下面有一個示例程式(一個較大程式的一部分),我需要將一個指向字串的指標(char 的雙指標)傳遞給一個函式,并在函式內修改該字串。實作這一目標的最佳方法是什么?
#include <string.h>
#include <stdio.h>
int incr(char **ptr)
{
char ar[104];
scanf("%s\n",ar);
*ptr = ar;
// this prints the string correctly
printf("%s\n",*ptr);
return 0;
}
int main(void)
{
char *d;
// pass the string (char array) to function
// expecting the input from scanf to be stored
// in this pointer (modified by the function)
incr(&d);
printf("%s\n",d);
return 0;
}
valgrind 的輸出:
$ gcc test.c -o terst
$ valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./terst
==1346438== Memcheck, a memory error detector
==1346438== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1346438== Using Valgrind-3.16.0 and LibVEX; rerun with -h for copyright info
==1346438== Command: ./terst
==1346438==
Sampletexttodisplay
Sampletexttodisplay
==1346438== Conditional jump or move depends on uninitialised value(s)
==1346438== at 0x4C38329: strlen (vg_replace_strmem.c:459)
==1346438== by 0x4EB48D5: puts (in /usr/lib64/libc-2.28.so)
==1346438== by 0x400658: main (in prog/terst)
==1346438==
==1346438== Conditional jump or move depends on uninitialised value(s)
==1346438== at 0x4C38338: strlen (vg_replace_strmem.c:459)
==1346438== by 0x4EB48D5: puts (in /usr/lib64/libc-2.28.so)
==1346438== by 0x400658: main (in prog/terst)
==1346438==
==1346438== Conditional jump or move depends on uninitialised value(s)
==1346438== at 0x4EBE86D: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EB4992: puts (in /usr/lib64/libc-2.28.so)
==1346438== by 0x400658: main (in prog/terst)
==1346438==
==1346438== Conditional jump or move depends on uninitialised value(s)
==1346438== at 0x4EBE87F: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EB4992: puts (in /usr/lib64/libc-2.28.so)
==1346438== by 0x400658: main (in prog/terst)
==1346438==
==1346438== Syscall param write(buf) points to uninitialised byte(s)
==1346438== at 0x4F2F648: write (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EBE1FC: _IO_file_write@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EBD56E: new_do_write (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EBF2B8: _IO_do_write@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EBF692: _IO_file_overflow@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EB4A61: puts (in /usr/lib64/libc-2.28.so)
==1346438== by 0x400658: main (in prog/terst)
==1346438== Address 0x5207490 is 16 bytes inside a block of size 1,024 alloc'd
==1346438== at 0x4C34F0B: malloc (vg_replace_malloc.c:307)
==1346438== by 0x4EB260F: _IO_file_doallocate (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EC04BF: _IO_doallocbuf (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EBF727: _IO_file_overflow@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EBE8CE: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib64/libc-2.28.so)
==1346438== by 0x4EB4992: puts (in /usr/lib64/libc-2.28.so)
==1346438== by 0x400631: incr (in prog/terst)
==1346438== by 0x40064C: main (prog/terst)
==1346438==
)??lay
==1346438==
==1346438== HEAP SUMMARY:
==1346438== in use at exit: 0 bytes in 0 blocks
==1346438== total heap usage: 2 allocs, 2 frees, 2,048 bytes allocated
==1346438==
==1346438== All heap blocks were freed -- no leaks are possible
==1346438==
==1346438== Use --track-origins=yes to see where uninitialised values come from
==1346438== For lists of detected and suppressed errors, rerun with: -s
==1346438== ERROR SUMMARY: 40 errors from 5 contexts (suppressed: 0 from 0)
$
如您所見,main 中的 printf 不會列印預期的輸出“Sampletexttodisplay”(它只是輸出一堆垃圾),而 incr 函式中的 printf 會列印。所以會發生一些事情,原始指標被修改,但沒有修改到所需的字串。是否有快速解決方案,或者是否有一些更優選的方法來修改函式內的字串?感謝幫助。
uj5u.com熱心網友回復:
d已經是指標了,可以直接使用。但首先,您需要使用malloc().
另外,scanf("%s\n",d)不應該使用,末尾的換行符會使scanf()填充永遠等待輸入。使用時自動洗掉末尾鍵入的換行符scanf()。而只是使用scanf("%s",d).
作業代碼:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int incr(char *ptr)
{
scanf("%s",ptr);
printf("%s\n",ptr);
return 0;
}
int main(void)
{
char *d = malloc(sizeof(char) * 104);
// pass the string (char array) to function
// expecting the input from scanf to be stored
// in this pointer (modified by the function)
incr(d);
printf("%s\n",d);
free(d);
return 0;
}
uj5u.com熱心網友回復:
正如@RetiredNinja 在評論中所建議的,問題在于陣列的生命周期ar。該陣列在呼叫 期間分配在堆疊上incr。之后incr的回報,一個指向該記憶體位置可以作業,但它可能不會。
如果記憶體是動態分配的,它的生命周期不會系結到函式呼叫,它將保持有效,直到它被釋放free。
還建議您在scanf.
int incr(char **ptr)
{
char *ar = malloc(104); // char is 1 byte, so this allocates 104 chars
scanf("3s", ar);
*ptr = ar;
printf("%s\n", *ptr);
return 0;
}
或者,沒有必要這樣做,我們可以使用scanf將文本直接讀入ptr.
int incr(char **ptr)
{
scanf("3s", *ptr);
printf("%s\n", *ptr);
return 0;
}
這有兩個優點。它避免了這個函式動態分配記憶體,我們可能會忘記。這也意味著最初分配的任何記憶體ptr都不會泄漏。
然而,它剝奪了我們在更改之前掃描文本并驗證它的機會ptr。
uj5u.com熱心網友回復:
您成功“修改了函式內的字串”。好吧實際上并沒有修改,更像是通過列印創建。您可以在函式內輸出它,而您存盤字串的陣列仍然有效且可訪問,即直到函式執行結束。
之后,不再允許訪問現在不存在的區域變數。如果你不這樣做,一切都會好起來的——除了一個稍微奇怪的 API,它允許保留一個指向函式之外禁止的東西的指標。以這種方式指向 poniter 構造的指標與從函式回傳禁止指標非常相似。
然后您確實訪問了禁止的、不再存在的字串。這當然失敗了。
您可以將指標的引數(在我看來不是指向指標的指標,這是不需要的)傳遞給字串或至少傳遞給合法記憶體;這必須是您的介面定義的一部分“親愛的用戶,您提交的指標必須指向有效且足夠大的字串合法記憶體。”
或者,您可以堅持使用指向指標介面的指標,并定義之后的指標將指向合適的內容。為此,您必須以合法方式創建此類合法記憶體,例如malloc(). 并且您的介面規范必須包括“親愛的用戶,指標到指標引數參考的指標隨后將指向合法記憶體。如果您呼叫此函式,您有責任在使用結束時正確釋放它。 ”
uj5u.com熱心網友回復:
一些事情:從您的評論中,您似乎
您不是在嘗試修改指標,而是在嘗試修改它指向的內容,因此您可以傳遞原始指標。
您的代碼失敗的地方是,正如 Retired Ninja 在他的評論中指出的那樣,當您離開函式時,您的原始字符陣列將被銷毀,因為它是一個區域變數。為避免這種情況,您應該在 main.js 中宣告它。
我在下面寫了我相信你打算做的事情。在這里,我們可以看到正在發生的事情:
- 您可以使用 char ar[104] 為陣列創建空間。這里 ar 指向你的陣列
- 您將 ar 傳遞給您的函式 incr,在那里創建它的本地副本并將其存盤為 ptr。但是由于我們不是要更改指標,而是要更改它所指向的內容,所以沒關系。
- 資料被寫入到 ptr 所指向的位置,這與我們原來的 ar 指標所指向的位置相同。
#include <string.h>
#include <stdio.h>
int incr(char* ptr)
{
scanf("%s\n",ptr);
printf("%s\n",ptr);
return 0;
}
int main(void)
{
char ar[104];
incr(ar);
printf("%s\n",d);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/385165.html
上一篇:如何在C中將函式指標陣列的函式指標作為函式引數傳遞?
下一篇:在函式中使用字串陣列
