[英]Why does the pointer only work for normal scanf rather than a custom function?
我去為我的語言計划一個輸入函數,它被稱為take()
。 我首先用 C 和 Python 構建它,但為了這個問題,我將使用 C:
char *take(char *text) {
char result[256];
printf("%s", text); scanf("%s", result);
return result;
}
這是我的想法,我想在實際程序中嘗試一下:
int main() {
char name[256];
name = take("What's your name? ");
sayLn("Hello, " + name + "."); // The say() function, except it prints out a new line too
}
但是當我嘗試編譯時出現了 4 個錯誤,其中 2 個是因為輸入函數:
Hello.c:13:12: error: address of stack memory associated with local variable 'result' returned [-Werror,-Wreturn-stack-address]
return result;
^~~~~~
Hello.c:18:10: error: array type 'char [256]' is not assignable
name = take("What's your name? ");
~~~~ ^
但是,如果我嘗試將源代碼放入正常程序中,它就可以工作!
int main() {
char name[256];
printf("What's your name? "); scanf("%s", name);
sayLn("Hello there!"); // Had to change this because of the other 2 errors
}
問:為什么會這樣? 我如何解決它?
您不能返回指向局部變量的指針,也不能將指針分配給數組。 通常做這種事情的方式是傳遞結果的地址。 我真的不認為scanf
是在這里使用的正確方法,因為阻止名稱包含空格似乎很奇怪,但為了演示起見,您可以執行以下操作:
#include <stdio.h>
#include <assert.h>
int
take(const char *prompt, char *result, size_t siz)
{
char fmt[32];
printf("%s", prompt);
assert(siz < 10e28); /* %Ns for N < SIZE_MAX must fit in fmt */
sprintf(fmt, "%%%zus", siz - 1);
return scanf(fmt, result);
}
int
main(void)
{
char name[256];
if( take("What's your name? ", name, sizeof name) == 1 ) {
printf("Hello, %s.\n", name);
}
return 0;
}
請注意,您應該使用scanf("%s", ...)
你應該使用相同的方式gets
。 也就是說,您應該僅將其用作不良代碼的演示。 您必須始終在說明符中使用最大寬度以防止溢出。 也就是說,您應該使用%Ns
(例如%255s
)而不是%s
來寫入任意大量的數據,其中 N 比 scanf 將寫入的數組的大小小 1。
您的方法存在多個問題:
take()
返回一個指向本地自動數組的指針:在函數返回后訪問它具有未定義的行為。
您應該將take()
的返回值存儲到main()
的char*
中。
C 中的+
運算符無法進行字符串連接。
有兩種方法可以解決這些問題:
take()
分配一個字符串的副本並返回一個指向它的指針,但你需要在使用后釋放這個對象:#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sayLn(const char *s) {
printf("%s\n", s);
}
char *take(const char *text) {
char result[256];
printf("%s", text);
*result = '\0'; // return an empty string on input error
scanf("%s", result);
return strdup(result);
}
int main() {
char message[300];
char *name = take("What's your name? ");
snprintf(message, sizeof message, "Hello, %s.", name);
free(name);
sayLn(message);
return 0;
}
take
:#include <stdio.h>
void sayLn(const char *s) {
printf("%s\n", s);
}
char *take(const char *prompt, char *result, size_t size) {
char spec[32];
if (size == 0)
return NULL;
// construct a conversion specification that limits the input to avoid a buffer overflow
snprintf(spec, sizeof spec, "%%%zus", size - 1);
printf("%s", text);
*result = '\0'; // return an empty string on input error
scanf(spec, result);
return result;
}
int main() {
char name[256];
char message[300];
take("What's your name? ", name, sizeof name);
snprintf(message, sizeof message, "Hello, %s.", name);
sayLn(message);
return 0;
}
嘗試將其設為指針:
int main() {
char *name;
name = take("What's your name? ");
sayLn("Hello, there!");
}
遺憾的是,它實際上並沒有解決您關於返回堆棧內存的錯誤。 嘗試自己修復。
您正在嘗試返回用數組而不是指針格式化的字符串。
嘗試這個:
char *take(char *text) {
printf("%s", text);
char *result = malloc(sizeof(char *));
scanf("%s", result);
return result;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.