我在一些腳本語言中相當能幹,但我終於強迫自己學習C語言。我只是在玩一些基本的東西(現在是I/O)。我怎樣才能分配堆內存,在分配的內存中存儲一個字符串,然後吐出來呢?這就是我現在所擁有的,我怎樣才能使它正常工作?Malloc和scanf
目前我收到奇怪的輸出像'8'\'。
我在一些腳本語言中相當能幹,但我終於強迫自己學習C語言。我只是在玩一些基本的東西(現在是I/O)。我怎樣才能分配堆內存,在分配的內存中存儲一個字符串,然後吐出來呢?這就是我現在所擁有的,我怎樣才能使它正常工作?Malloc和scanf
目前我收到奇怪的輸出像'8'\'。
char *toParseStr = (char*)malloc(10);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
首先,scanf
中的字符串指定了它將要接收的輸入。爲了在接受鍵盤輸入之前顯示一個字符串,使用printf
,如圖所示。
其次,您不需要取消toParseStr
,因爲它指向的大小爲10的字符數組與您分配的malloc
。 如果您正在使用的功能,它會指向另一個內存位置,然後&toParseStr
是必需的。
例如,假設您想編寫一個函數來分配內存。然後,您需要&toParseStr
,因爲您正在更改指針變量的內容(這是內存中的一個地址---您可以通過打印其內容來查看自己的內容)。
void AllocateString(char ** ptr_string, const int n)
{
*ptr_string = (char*)malloc(n)
}
正如你可以看到,它接受char ** ptr_string
其內容,其存儲一個指示字的存儲器位置的指針,其將存儲所分配的塊的第一個字節的存儲器地址(malloc
操作之後)的n
字節(現在它有一些垃圾內存地址,因爲它是未初始化的)。
int main(int argc, char *argv[])
{
char *toParseStr;
const int n = 10;
printf("Garbage: %p\n",toParseStr);
AllocateString(&toParseStr,n);
printf("Address of the first element of a contiguous array of %d bytes: %p\n",n,toParseStr);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
return 0;
}
第三,建議釋放你分配的內存。即使這是你的整個程序,並且這個內存將在程序退出時被釋放,但這仍然是一個好習慣。
即使在一個小程序中也可以釋放+1。讓我想起「小滴滴變成海洋」。 ;-) – 2010-07-21 03:54:01
您應該在打印提示符並調用scanf之間調用'fflush(stdout);'。大多數實現會做到這一點,讓你彬彬有禮,但它不是強制性的。 – 2010-07-21 11:07:47
,因爲它已經是一個指針
也呼籲free(toParseStr)
你不需要toParseStr
之前&
在scanf
事後
根據bball的系統,可能需要在該printf中放置一個「\ n」,以便正確顯示事物。另外,10個字符是一個非常短的字符串。 – George 2010-07-21 02:35:56
雖然這是事實,但這並不是問題的根源(在這種情況下'&'是不必要的,但是無害的)。 – 2010-07-21 02:36:14
@Jerry它是無害的,因爲格式說明符沒有指定任何參數,但是一旦他修復它在你的答案中有一個%s就會導致段錯誤 – 2010-07-21 02:37:42
你需要給scanf
轉換格式,因此它知道你想讀一個字符串 - 現在,你只是顯示在你分配的內存中發生的任何垃圾。而不是試圖描述所有的問題,這裏的一些代碼,至少應該接近工作:
char *toParseStr = malloc(10);
printf("Enter a string: ");
scanf("%9s", toParseStr);
printf("\n%s\n", toParsestr);
/* Edit, added: */
free(toParseStr);
return 0;
編輯:在這種情況下,free
荷蘭國際集團字符串不作任何真正的區別,但像其他人那樣指出,它是是仍然是培養的好習慣。
+1正確使用'scanf'中的'%9s'。 – sarnold 2010-07-21 02:42:47
與某些人的看法相反,在執行讀取操作之前,刷新'stdout'對於確保提示出現是不必要的,除非實現被正確地破壞了。對於那些真正關心的人,請參閱§7.19.3。如果可以確定*不*指向交互設備,'stdout'只能被完全緩衝。 – 2010-07-21 03:02:06
你錯了。 'stdout'仍然可以**行緩衝**,這意味着直到打印換行符纔會顯示任何內容。 POSIX建議實現在讀取時刷新stdout和其他這樣的行緩衝流,但是掃描行緩衝流的打開文件列表(特別是使用線程和鎖定)並且實現可能選擇不執行所以出於很好的理由。據我所知,ISO C對緩衝語義幾乎沒有要求。所以你**應該**沖洗! – 2010-07-21 11:10:43
首先,使程序不能正常工作的錯誤:scanf(3)
採用格式字符串,就像printf(3)
一樣,不是爲用戶打印的字符串。其次,您傳遞的是指針toParseStr
的地址,而不是指針toParseStr
。
我也從您的電話malloc(3)
刪除不必要的演員。
你的程序仍然需要改進的地方是使用scanf(3)
的a
選項爲你分配內存 - 這樣一些小丑將十個字符放入你的字符串中並不會開始st on無關的內存。 (是的,C就會讓別人幾乎覆蓋整個地址空間有了這個程序,書面巨安全漏洞。:)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = malloc(10);
printf("Enter a short string: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
return 0;
}
'scanf'沒有'a'選項。這是一個GNU擴展,它不僅是非標準的,而且還有** CONFLICTS **和ISO C('%a'是讀取浮點數的說明符之一!)。應該絕對避免。 – 2010-07-21 11:15:29
謝謝;我不知道這個擴展與ISO C. – sarnold 2010-07-22 09:19:51
數據使用scanf()
(或fscanf()
你不控制)與標準「 %s「說明符是讓你自己陷入緩衝區溢出困境的一種近乎確定的方式。
經典的例子是,我在你的程序中輸入字符串「這個字符串超過10個字符」,混沌將隨之而來,貓和狗將開始一起睡覺,裸露的奇點可能會出現並消耗地球(大多數人只是陳述「未定義的行爲」,但我認爲我的描述更好)。
我積極勸阻使用無法提供保護的功能。我會敦促你(特別是作爲C的新手)使用fgets()
來讀取你的輸入,因爲你可以更容易地控制緩衝區溢出,它比scanf()
更適合於簡單的線路輸入。
一旦你有了一條線,你就可以在其上調用sscanf()
到你心中的內容,順便說一句,你不需要在這個特定的情況下做,因爲你只是得到一個原始字符串。
我會用:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSZ 10
int main(int argc, char *argv[]) {
char *toParseStr = malloc(BUFFSZ+2);
if (toParseStr == NULL) {
printf ("Could not allocate memory!\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (toParseStr, BUFFSZ+2, stdin) == NULL) {
printf ("\nGot end of file!\n");
return 1;
}
printf("Your string was: %s",toParseStr);
if (toParseStr[strlen (toParseStr) - 1] != '\n') {
printf ("\nIn addition, your string was too long!\n");
}
free (toParseStr);
return 0;
}
+1有衝突,但我補充說,雖然'fgets'確實有優勢,scanf和fscanf都有防止緩衝區溢出的措施。 – 2010-07-21 02:46:06
@Jerry雖然我很少看到人們用「%s」使用寬度說明符,但這是一個很好的觀點:-)因爲我的大多數控制檯I/O代碼都傾向於具有基於行的輸入,所以%s不適合獲得空白空間。但是,由於您的答案在這種情況下確實是正確的,所以您+1。 – paxdiablo 2010-07-21 03:02:12
另一個有趣的可能性是'scanf(「%9 [^ \ n]」,your_string);'''scanf'的面向行的字符串輸入,無論值多少錢。 – 2010-07-21 03:10:23
你並不需要從'的malloc和''包括投的返回類型'在ISO C(3)。 –
sarnold
2010-07-21 02:34:34
值得指出的是,您應該在這裏使用堆棧。 – dicroce 2010-07-21 02:36:27