簡體   English   中英

為什么指針只適用於普通 scanf 而不是自定義函數?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM