簡體   English   中英

C中的指針問題? 對輸入進行排序的函數,作為字符串返回並在 main 中打印

[英]pointer problems in C? function to order inputs, return as string and print in main

我想編寫一個函數,它將接受兩個整數,三次,然后按第一個整數排序返回它們,並(現在)在 main 中打印它們(盡管最終我計划/希望切換到基於文件的結構來存儲並組織數據),但我認為我的指針可能有問題,即使我跳過連接(這看起來也可能是另一個單獨的問題),我嘗試過的所有內容都主要打印一個永遠不匹配的字符串(或沒有字符串)輸入,但打印語句表明所有循環分配都正常工作。

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

const char * entry()
{
    int n;
    int level;
    char habit1entry[6];
    char habit2entry[6];
    char habit3entry[6];
    for (int c = 0; c< 3; c++){
        printf("Habit #\n");
        scanf("%d", &n);
        printf("Level:\n");
        scanf("%d", &level);
        switch (n)
        {
            case 1:;
                sprintf(habit1entry, "|%d|%d|\n", n,level);
                printf("n = %d\n",n); 
                printf("%s\n",habit1entry);
                continue;
            case 2:;
                sprintf(habit2entry, "|%d|%d|\n", n,level);
                printf("n = %d\n",n);
                printf("%s\n",habit2entry);
                continue;
            case 3:;
                sprintf(habit3entry, "|%d|%d|\n", n,level);
                printf("n = %d\n",n);
                printf("%s\n",habit3entry);
                continue;
        }
    }
    strcat(habit2entry,habit3entry);
    printf("%s\n",habit2entry);
    strcat(habit1entry,habit2entry);
    printf("%s\n",habit1entry);
    char *fullEntry=habit3entry;
    printf("%s\n",fullEntry);

    return strdup(&fullEntry[0]);
}
int main(){
    const char * dataEntry = entry();
    //strcpy(dataEntry,entry());
    printf("Data:\n%s",dataEntry);
}

這是輸入 3 2 1 1 2 2 的輸出示例(在開關盒內正確打印之后):“

|2|2|

|1|1|
|2|2|
|2|2|
|
|2|2|
|
* 檢測到堆棧粉碎 * : ./a.out 終止
中止(核心轉儲)”

ps 抱歉,如果這一切聽起來很傻,這是我的第一個 C 項目(也是第一個真正的堆棧溢出帖子,請務必在 java、python 和 clojure 之間跳來跳去),我想學習一個操作系統類,它可以讓你從不了解 C 的情況下開始,但希望您自己掌握它及其難以找到的材料,這些材料可以在與我的背景知識和當前學習限制相匹配的范圍內通過對我的解釋進行深入研究的時間范圍內解釋 C 概念對我在其他語言中學到的編程概念的解釋大多是極其深奧的、令人難以置信的特定案例或過於簡單/冗余/無用的解釋。 不要抱怨或抱怨,練習使用不同的提問和尋找此類問題的答案的方法可能是件好事,但是理解此類事情的學習曲線(設置編譯器/json 文件只需要花費數小時發現 mcafee 正在刪除我的前任,我確信這是病毒的症狀,只是在我重新啟動一個次要的例行 Windows 更新后行為停止了,我不知道為什么)在傳統框架之外有時看起來更像是一個牆,我擔心也許我應該修改我的方法以避免浪費太多時間將我的頭撞到一系列非常堅固的牆壁上。 非常感謝任何和所有建議。

抽象形式的程序邏輯,你有很多問題:

  1. 您沒有為字符串提供足夠的空間
  2. 您的開關與您的 for 循環關系不大
  3. 變量的名稱對您來說無關緊要,但對程序來說卻很重要。 多加小心。
  4. 可能更多,但我已經忘記了
#include <stdio.h>
#include <string.h>

const char * entry()
{
    int n;
    int level;
    char habit1entry[21] = "";
    char habit2entry[14] = "";
    char habit3entry[7] = "";
    for (int c = 1; c < 4; c++){
        printf("Habit #\n");
        scanf("%d", &n);
        printf("Level:\n");
        scanf("%d", &level);
        switch (c)
        {
            case 1:;
                sprintf(habit1entry, "|%d|%d|\n", n,level % 10);
                printf("n = %d\n",n); 
                printf("He1: %s\n",habit1entry);
                continue;
            case 2:;
                sprintf(habit2entry, "|%d|%d|\n", n,level % 10);
                printf("n = %d\n",n);
                printf("He2 = %s\n",habit2entry);
                continue;
            case 3:;
                sprintf(habit3entry, "|%d|%d|\n", n,level % 10);
                printf("n = %d\n",n);
                printf("He3 = %s\n",habit3entry);
                continue;
        }
    }
    strcat(habit2entry,habit3entry);
    printf("H2 + H3 = %s\n",habit2entry);
    strcat(habit1entry,habit2entry);
    printf("H1 + H2 = %s\n",habit1entry);
    char *fullEntry=habit1entry;
    printf("FE: %s\n",fullEntry);

    return strdup(fullEntry);
}
int main(){
    const char * dataEntry = entry();
    //strcpy(dataEntry,entry());
    printf("Data:\n%s",dataEntry);
}

歡迎來到 C 的奇異而奇妙的世界。

我還沒有真正編譯和運行你的程序,只是快速通讀了一遍,盡管我給了你我的第一個想法。

編寫程序的方式已准備好產生堆棧溢出。 您在堆棧慣用條目上定義了三個(非常少)字符數組,因此您的 sprintf 肯定會炸毀您的堆棧,除非習慣和級別輸入都小於 10。習慣沒問題,因為您的開關只允許 1、2 或 3。如果習慣是別的什么,你的開關就什么都不做。

附帶說明: sprintf 並不是在我們注重安全的世界中真正使用的功能。 snprintf 是更好的選擇。 這里本身並不是一個真正的問題,因為您沒有傳遞用戶提供的數據,但這仍然不是一個好習慣。

接下來,您將字符數組 strcat 在一起,實際上保證了堆棧違規,但讓我們假設這是有效的; 您將 2 和 3 連接成習慣 2 條目,然后將 1 和 2 連接成習慣 1 條目。

接下來,您將創建一個指向習慣 3 條目(而不是習慣 1 條目)的指針並返回一個副本。

通過這樣做,您正在以一種溫和晦澀的方式分配堆。 被調用者將負責釋放此內存。 我總是喜歡顯式地 malloc 內存,然后 strcpy(或 memcpy)數據。現在當你 grep 代碼時,你只需要尋找 malloc。 此外,使用該函數的人會注意到 malloc,看到您已返回指針並意識到釋放它現在將是他的問題。

為了避免這些問題,一些程序員讓調用者為函數提供緩沖區。 推理是一個函數應該做一件事並且只做一件事。 在這種情況下,您正在做兩件事,分配內存並填充該內存。

在您的 switch 語句中,我注意到您的每個 case 標簽后跟一個空語句。 該行末尾的分號不是必需的:寫“case 1:”而不是“case 1:;” 您還可以在每個塊的末尾使用 continue。 這是允許的,但“中斷”更合適。 在這種情況下,它將具有相同的效果,但通常在 switch 之后會有更多的語句。 現在差異將變得明顯。 Continue 會直接跳到循環的頂部,break 會跳出 switch 並在那里繼續執行。

希望這能給你一些見解。

祝你好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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