50個C語言/C++程序員必會遇到的疑難解答

技術交流羣:782648055
1. getchar和system(“pause”)

相同點:都可以實現“暫停”效果

但實際過程,有區別。

getchar()是從輸入緩衝區中讀取一個字符。如果輸入緩衝區(使用scanf輸入的任何數據都是先被保存在輸入緩衝區中!)中沒有任何數據,那麼就暫停,直到用戶輸入任意數據並回車,程序才繼續往下執行。使用getchar()時,如果輸入緩衝區中還有數據,那麼就不能實現暫停效果。

system(“pause”)則與輸入緩衝區沒有任何關係,會直接暫停程序的執行,直到用戶按下任意一個按鍵(不需要在最後輸入回車符),纔會繼續執行。system(“pause”)還會有自動輸出提示信息:“請按任意鍵繼續. . .”而且這個提示信息是固定的,不能修改。

2. 頭文件的作用

如果在程序中使用了某個c語言預定了的函數,比如printf, 就需要把這個函數的“函數聲明”(相當於函數的“介紹”)包含到這個文件中。而這些函數的聲明都已經存放在對應的頭文件中,比如printf函數的函數聲明在stdio.h, 所以需要在程序中使用 #include <stdio.h>

在實際開發中,也會常常定義自己的頭文件,用來保存一些函數的函數聲明,其他文件如果想使用這些函數,就包含這個頭文件。具體用法在項目實戰環節再詳細介紹。

3. void

作用1:作爲函數的返回類型

函數的返回類型爲void, 就表示這個函數沒有返回值。

作用2:作爲函數的參數

函數後面的()用來寫參數,如果沒有參數,建議寫void, 告訴編譯器,這個函數沒有參數。如果不謝,編譯器也會認爲沒有參數。但是可能會告警,因爲編譯器怕你忘記寫參數了,如果寫void, 就是明確告訴編譯器,這個函數時沒有參數的。

作用3:

作爲void*, 表示指向任意類型的指針,在指針部分詳細介紹。

4. main函數

實際項目中,會很多函數,大項目中有幾千甚至幾萬個函數。main函數是程序的入口,也就是程序運行時,首先從main函數開始執行

5. 變量

變量的存儲位置

當程序員定義一個變量比如, char x;
這個變量x佔用一個字節,但是這個變量的具體存儲位置,是編譯器來決定的,程序員不能決定。但是程序員可以使用 &x來獲得變量x的存儲地址。

變量的含義:

學習編程,有一個捷徑,就是不要去糾結什麼語法知識。而是從解決問題入手。

程序的目的就是爲了解決問題的.

如果程序寫對了,但是解決不來問題,那這個程序也就是沒有任何意義的。

比如擁有一個問題,需要計算兩個數的和,也就是做加法。

需要你來設計一個程序,來實現這個加法功能。

那麼你就需要使用某個東西,來保存用戶輸入的兩個整數。

用什麼來保存呢?

使用“變量”!

需要定義幾個變量呢?

至少要定義3個。

分別用來保存用戶輸入的兩個整數,以及他們的和。

int a;

int b;

int s; //計算的結果。

6. printf和fprintf

printf 就是向屏幕打印信息


fprintf是向指定的文件打印信息。而一般的文件,都是保存在磁盤的,也就是硬盤。比如文件 C:/tmp/hello.c


printf其實是fprintf的一種特殊情況,就是把信息打印到一個特殊的文件(標準輸出設備),而默認的標註輸出設備就是屏幕(控制檯的屏幕)

7. gets和fgets

gets和fgets也是類似的。
gets是從鍵盤讀取一行字符串。
fgets是從指定的文件讀取一行字符串。
gets是fgets的一種特殊情況,就是向一個特殊的文件讀取,這個特殊的文件就是標準輸入設備,而默認的標準輸入設備就是鍵盤。

8. 數組的理解

比如每個星期有7天,你準備每天都要去跑步鍛鍊,計劃每天跑步的運動量。

假設:

星期日:3000米,

星期1:5000米

星期2:4000米

星期3:3000米

星期4:1000米

星期5:2000米

星期6:8000米

此時就可以定義一個數組:

int run[7] = {3000, 5000, 4000, 3000, 1000, 2000, 8000};

這個數組的數組名稱是run, 包含7個整數。第一個整數用run[0]表示, 最有一個數組用run[6]表示。

這7個整數連續存儲在內存中,第一個run[0]的存儲地址最小,run[1]緊跟着存儲在run[0]後面。

run包含7個成員,每個成員都是一個整數,每個整數佔用4個字節,所以run一共佔用 4*7=28個字節。所以: sizeof(run) == 28

9. 編譯報錯-implicit declaration

10. if的條件判斷

任何if判斷語句,都要滿足條件爲真,才執行

這裏的條件爲真,不是說其中某個變量的值是真是假,而是指整個表達式的值是否爲真。

比如,file的值爲NULL(也就是0, 就是假)

if (file) {

//不會執行

}

if (file == NULL) { // 雖然file是假,但是 file == NULL 就是真!

///會執行

}

11. 邏輯值

普通表達式和真假沒有關係
1+2 和真假無關
strcmp(name1, name2)和真假無關,這個函數的值就是一個整數。

但是所有比較運算的結果,都是邏輯鎮,也就是真或者假
比如:
1+2 == 3 結果是 真
strcmp(name1,name2) == 0 結果是真或者假
1+2 > 3 結果是假

12. fscanf

13. 回車符

\r\n是屬於文件的格式問題。


當把回車符(\n) 保存爲\r\n時,這個回車符,在文件中實際佔用兩個字節,分別爲'\r' '\n'。
當使用fgets讀取這個文件時,會把文件中的'\r' '\n' 這兩個字節,識別爲一個字符 '\n'
 

所以:字符串 “123\n”在文件中佔用5個字節, 即保存爲"123\r\n",
但是再使用fgets讀取這一行時,讀到的只是 “123\n”, 也就是把\r\n識別爲一個字符\n, 另外在最後加上一個字符串結束符\0

(注意,字符串結束符\0,僅在c語言中使用,用來表示字符串的結束,在文件中是沒有字符串結束符的,除非特別的去寫入這個字符)

14. gcc沒有安裝

如果系統是windows7或者windowsXP, 按照這個視頻來做,建議一邊看一邊做:

 

如果系統是windows10, 按照這個視頻來做,建議一邊看一邊做:(羣文件裏有)

 



軟件MinGW到羣裏直接下載:

 

15. 輸入緩衝區

我們在使用scanf或者getchar或者gets收入數據時,從鍵盤輸入的數據,都是先進入”輸入緩衝區“。

scanf先在輸入緩衝區中檢查時候有數據,如果輸入緩衝區中有數據,就直接從輸入緩衝區中讀取數據。

如果輸入緩衝區中是空的,程序就會暫停,等待用戶輸入數據。

比如:scanf("%c", &x);

如果輸入abc和回車, 但是實際只讀一個字符,所以輸入緩衝區中還會剩下 'a' , 'b' 和 '\n'

如果後面還有一個輸入語句:

scanf("%c", &y); 或者 y = getchar();

此時就直接從輸入緩衝區中讀取一個字符 'b', 用戶就沒有機會輸入數據了。

或者右面還有一個輸入語句:

scanf(("%d", &y);

此時直接從輸入緩衝區中讀取一個整數,但是輸入緩衝區中是’a’和’b’, 並不是整數,導致用戶沒有機會輸入數據,而去把’a’和’b’當整數輸入,結果當然是輸入失敗。

如果輸入緩衝區中還剩下數據,就導致後面的scanf或者getchar語句執行時,程序不會暫停讓用戶輸入,而是直接從輸入緩衝區中獲取數據。

如果輸入緩衝區中還有回車符,就會導致後面的gets語句執行時,程序不會暫停讓用戶輸入,而是直接從輸入緩衝區中讀取一個空行!(就是一個空字符串),因爲 gets是遇到回車符符就結束。

爲了解決這個問題,就可以使用 fflush(stdin);

fflush(stdin) 就會把輸入緩衝區的所有數據都清空。

使得後面的scanf或者getchar能夠暫停,讓用戶重新輸入新的數據。

補充:scanf語句中使用 %d 或者 %f 或者 %lf時, 或自動跳過 空格,回車符,和製表符。
只有%c , 不會跳過任何字符。

16. 字符串結束符

我們編寫的源程序,比如 hello.c

這些程序其實是給人看的,計算機並不懂,計算機也不能執行 hello.c
需要使用編譯器(比如gcc) 把這個程序hello.c轉換爲計算機能夠識別的可執行文件(.exe文件)
比如: gcc hello.c
就會把hello.c 轉換爲 可執行文件 a.exe
這個a.exe文件此時還是保存在硬盤裏。


當在cmd窗口中, 執行這個a.exe文件時,

會把硬盤中的a.exe文件 複製到內存中執行!


a.exe在內存中執行的過程中,

如果從文件user.txt讀取一個字符串,並保存到數組中時,

那麼此時會在數組中的字符串最後加一個字符串傳結束符

17. getc和fgetc

getc和fgetc的作用是一樣的。

getc其實是一個宏,宏的具體用法在後面會詳細介紹。

getc的定義如下:
#define getc(fp) fgetc(fp)

也就是說,代碼中如果有 getc(file),
就會把它替換成:fgetc(file)


在一般的使用場合中,使用 getc和fgetc的效果是一樣的

18. close和fclose

這個是我的誤操作了, 應該使用fclose
fclose是C語言的接口
close也是關閉文件的作用,但是 close是系統級的接口,也就是說,比fclose更底層,更接近操作系統的函數。

19. fscanf的多行匹配

對於如下文本:

張三丰 Tel:13507318888 Addr:武當

劉備 Tel:13802289999 Addr:成都

馬雲 Tel:13904256666 Addr:杭州

馬化騰 Tel:13107551111 Addr:深圳

可以循環使用如下代碼讀取:

fscanf(file, "%s Tel:%s Addr:%s\n", name, tel, addr);

但是不加回車符,使用如下語句也能讀取:

fscanf(file, "%s Tel:%s Addr:%s", name, tel, addr);

這是是因爲:

使用fscanf(file,"%s Tel:%s Addr:%s",name_tmp,tel,addr),匹配到第一行的第2個%s時,剛好把第一個行中,除了最後的回車符以外,匹配完。此時第一行還剩下一個回車符。接着進入第2輪循環,又開始使用scanf匹配,但是注意,是從文件的上一次匹配結束的位置繼續匹配,也就是第一行行尾的回車符爲止,在這個格式字符串中,第一個是%s,所以會跳過第一行行尾的回車符,從而匹配成功。

如果文件的內容是這樣的格式,就必須在格式字符串的最後加上\n了

姓名:張三丰 電話:13243879188

姓名:張四風 電話:13243879199

總結:需要特別注意fscanf的格式字符串中最後的\n的作用。

20. notepad++/vs亂碼

 

 

然後重新創建一個文件,就默認是ANSI編碼了,在cmd就可以正常輸出中文了

vs亂碼:

如果控制檯的編碼和程序的編碼一致,還是有中文亂碼,就需要修改控制檯的屬性,

右擊控制檯標題欄,選擇“屬性”,勾選“使用舊版控制檯”

然後再重新運行。

 

21. scanf的返回值

scanf的返回值,表示成功輸入的數據個數。

例如:

int x;

scanf("%d", &x);

當輸入100時,x的值是100

如果輸入a, 那麼將導致scanf執行失敗,此時x的值還是原來的值,而x沒有設置初始值,所以將是一個不確定的值,一般會是一個很大的值。

如果要考慮合法性,可以使用:

int x;

int ret;

ret = scanf("%d", &x);

if (ret <= 0) {

printf("輸入錯誤");

exit(1);

}

scanf的返回值,表示成功輸入的數據個數。

22. <或<=

<=表示小於或者等於,

5 < 6 是真

5 < 5 是假

5 <= 6 是真

5 <=6 就相當於:

5 < 6 || 5==6

根據實際需求使用,可以隨時使用< 或 <=

比如, 需要循環10次,可以使用

for (int i=0; i<10; i++)

也可以使用

for (int i=0; i<=9; i++)

23. 結構體的含義

這樣問,說明還沒有理解結構體的含義。
結構體變量,包含多個子變量。
比如已經定義了結構體 struct student類型。
這個結構體類型中,含有name成員(一個字符數組)

那麼如果有如下兩個結構體變量:
struct studen s1;
struct student s2;

那麼s1中含有name成員
s2中也含有name成員

如果只用name來表示,就無法區別是s1的name還是s2的name

結構體,本質上是一種“數據類型”,和int類型、char類型同等地位!
結構體,不是一個變量!
使用結構體,可以定義任何多個這種結構體類型的變量。

24. 彈出窗口

#include <windows.h>
#include <stdio.h>
int main() {
 int ret;
 
 ret = MessageBox(NULL,"我愛你!","",MB_OKCANCEL|MB_SETFOREGROUND);
 if   (ret == 1) {
 MessageBox(NULL,"我再想想..","", MB_OK|MB_SETFOREGROUND);
 }   else if (ret == 2) {
 MessageBox(NULL,"開玩笑的","",MB_OK|MB_SETFOREGROUND);
 }
 
 return   0;
}

 

25. 遠程後不能控制系統

https://jingyan.baidu.com/article/6b182309976683ba58e159c3.html

 

26. 4996錯誤

關閉VS警告 warning C4996

vs認爲scanf, f_open等函數不安全,編譯時,會出現如上4996警告。

方法1:修改項目的項目屬性

 

方法2:

在出現問題的文件中的頭文件後面,添加:

#pragma warning(disable:4996)

 

27. TeamViewer的使用

安裝:

 

28. break和continue的作用

break使用的場合比較多,在while語句,for語句,switch語句,都可以使用。

在while語句和for語句中,break的作用,就是直接結束結束循環,跳轉到該循環語句之後的語句執行。在多重嵌套循環中,break只能跳出所在那一層循環。

在switch語句中,break的作用,就是直接結束switch語句,跳轉到switch後面的語句執行。

continue語句,在while語句,for語句中都可以使用。
在while或for語句中,如果遇到continue語句,就直接結束本次循環,進入下一輪循環的判定語句。

特別注意的是,在for循環中,如果遇到了continue語句,還是會先執行for語句中第3個表達式,然後再判斷第2個表達式。

29. strlen

 

30. 逗號表達式

#include <stdio.h>
 
int main(void){
 int   x,y;
 //先計算x=10
 x   = 10, 11, 12; 
 
 //(10,11,12)這個逗號表達式的值的12,最後執行賦值運算
 y   = (10,11,12); 
 
 printf("x=%d\n",   x);
 printf("y=%d\n",   y);
 return   0;
}
 

31. vs不能使用scanf等函數

方法一:把scanf改爲scanf_s;.

方法二:無需在程序最前面加那行代碼,只需在新建項目時取消勾選“SDL檢查”即可;

方法三:若項目已建立好,在項目屬性裏關閉SDL也行;

32. scanf,fscanf 讀字符串

33. strcmp

34. 擴展名

windowsXP配置方式

 

再單擊確定。

windows10:

 

35. 密碼輸入

#include<conio.h>
#include<stdio.h>
 
int main(void)
{
 char   pwd[32];
 int   ch;
 int   i = 0;
 while   (1) {
 ch   = getch();
 if   (ch == '\r') {
 break;
 }
 pwd[i]   = ch;
 i++;
 putch('*');
 }
 pwd[i]   = 0;
 printf("\n您輸入的密碼是:%s\n", pwd);
 return   0;
}
 

或者:

void input_pwd(char *pwd, int max_len) {
 char   c;
 int   i = 0;
 
 printf("Please   input pwd: ");
 
 while   (1) {
 c   = getch();
  // getch不從輸入緩衝區中讀取
 //在getch中,把回車按鍵輸入,識別爲回車符'\r'
 //在getchar中,把回車按鍵輸入,識別爲換行符'\n'
 if   (c == '\r' || i >= max_len) { 
 pwd[i]   = 0;
 break;
 }
 pwd[i++]   = c;
 printf("*",   c);
 }
}

36 虛擬機打開失敗

 

需要重啓系統,然後按一個快捷鍵(不同的電腦,按鍵不同,可以搜索“自己的電腦型號 進入BIOS”),進入BIOS

然後在BIOS界面中,找到一個 virtualization相關的一個選項,設置爲Enable, 然後按F10退出重啓即可。

37 可執行文件名同名

如果程序文件名是 hello.c

那麼編譯時使用:gcc hello.c

得到的可執行文件就是 a.exe

如果再使用: gcc test.c

得到的可執行文件 a.exe就會覆蓋原來的a.exe

可以使用 -o選項來指定生成的可執行文件名

例如:

gcc hello.c -o myHello 得到的可執行文件的文件名是 myHello

gcc test.c -o myTest 得到的可執行文件的文件名是 myTest

-o後面可以使用任意名稱。

38 變量的作用域

變量的定義,比如 int s = 0; 或 int s;

如果這個變量的定義放在某個 { }內,那麼這個變量只能在這個大括號內生存,也就是說,只能在這個大括號有效

{
 int s = 0;
 {
 int s = 10; 
 printf("s=%d\n", x); //打印s=10, 如果小範圍的某個變量,如果和外面的某個變量同名,那麼在這個小範圍內,都認爲是小範圍的變量

 }
 printf("s=%d\n", x); //打印s=0
}
 

比如,如果你的某個同班同學叫馬雲,那麼在這個班裏,凡是說馬雲的,都是說班上的這個同學。

出了班級,在學校裏或者在社會上,凡是說馬雲的,就是阿里巴巴的馬雲。

 

39 循環體內變量的初始化

 

例如:

#include <stdio.h>
int main(void) {
 int   i;
 for   (i=0; i<10; i++) {
 int   s = 0;
 s   += 1;
 printf("s=%d\n",   s); //始終打印s=1
 }
 return   0;
}
 

40 逗號表達式

(表達式1, 表達式2, 表達方式3, ... , 表達式n)

當用()把多個表達式括起來,中間用逗號隔開時, 一起構成一個整體,稱爲逗號表達式.

整個逗號表達式的值, 是()中最右邊一個表達式的值.

比如(3, 5, 8)的值是8, (1+2, 2+5, 3+4)的值是 3+4, 也就是7

 

36.

41 loadimage出錯

42 類的定義中初始化數據成員

在類的定義中,直接對數據成員初始化,在老標準的C++中是不支持這樣做的。

但是在C++11中,是支持這種寫法的!

vs2010, 只支持少部分c++11特性,大部分C++11的新特性都不支持。

在類的定義中,直接對數據成員初始化,在vs2010中也是不支持的,但是在vs2015或者更高的版本中支持。

43 丟失api-ms-win-crt-conio-|1-1-0.dll

解決方案:

https://jingyan.baidu.com/article/851fbc3797531e3e1f15abea.html?qq-pf-to=pcqq.group

44 for循環不支持

for( int i=0; i<10; i++) {

//

這種方式(在for循環的第一行中的第一個分號之前,定義變量)在老版本的C語言中,是不支持的。在C++中是支持的。

新版本(C99版本)支持,

在編譯時,最後加一個 -std=c99 來指定編譯版本。

比如: gcc hello.c -std=c99

45代碼戰爭忘記密碼

 

 

然後在該郵箱中,打開郵件中的重置鏈接。

如果重置失敗,就只有重新註冊一個新賬號。

46. 305輸出1

305 按%c輸出, 就是按照char類型輸出
char只有1個字節,而305需要2個字節才能表示,所以就只取最低字節
也就是305, 最低字節是 305-256 = 49
而49按%c輸出,就是輸出ASCII值爲49的字符, 就是字符1
所以輸出1

47. scanf_s錯誤

//scanf_s("%s", x, ); //在vc++中正確,在vs中錯誤

scanf_s("%s", x, sizeof(x)); //正確

scanf_s中,最好再加上一個參數,從來最多接收多少個字節的數據。

在vc++(vs的c++版本)中,不需要第3個參數來表示最大數據長度

在vs中,必須要使用第3個參數來表示最大數據長度

scanf_s("%s", x, sizeof(x));

在vc++中,輸入ctrl+z 回車 scanf_s就返回EOF(-1)

在vs中,連續輸入兩次或三次ctrl+z 回車, scanf_s才返回EOF(-1)

48. 不顯示行號

 

 

49. vs2010安裝失敗

Github只是一個提供存儲空間的服務器,用來存儲git倉庫

Github已經成爲了管理軟件開發以及發現已有代碼的首選方法

Github公有倉庫免費,私有倉庫要收費

你可以參與別人的開源項目,也可以讓別人參與你的開源項目

提示:

VS2010 "缺少dlmgr.dll 無法繼續執行代碼。重新安裝程序可能會解決此問題

64位系統:
    複製dll文件到C:\Windows\System32
    複製dll文件到C:\Windows\SysWOW64
32位系統:
    複製xdll到C:\Windows\System32

50. vc++錯誤:VS2010 error MSB8008: 指定的平臺工具集(v140)未安裝或無效.請確保選擇受支持的 Platforom

 

把平臺工具集,改爲v100

一些入門的視頻教程和小遊戲項目的教程都在B站上

整理不易,點個贊吧~~~如果想和我一起學習,請關注我或者私信我,我會給大家準備一套免費的C/C++學習資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章