前言
想必剛接觸C語言的同學(xué)們不知道C語言是什么?,有什么用,那么你來對了,本系列就會帶你入門C語言,從入門到“入土”,開玩笑的,正如標題所說,本教程首先對C語言有一個初步的認識,能夠看懂別人寫的是什么,有一個大概的框架,那么,我要開始講解了。 這一章主要是初始C語言的一個大綱。
一、什么是C語言
C語言是什么?
-
語言:漢語,日語,英語等。語言是一個自然語言,是人與人交流的語言。
計算機語言:類比過來,是人與計算機之間的交流。 -
C語言是一門通用計算機編程語言,廣泛應(yīng)用于底層開發(fā)。C語言的設(shè)計目標是提供一種能以簡易 的方式編譯、處理低級存儲器、產(chǎn)生少量的機器碼以及不需要任何運行環(huán)境支持便能運行的編程語 言。 盡管C語言提供了許多低級處理的功能,但仍然保持著良好跨平臺的特性
二、第一個C語言程序
- 我們在了解完C語言是什么后,我們需要了解如何使用集成開發(fā)環(huán)境去完成第一個C語言程序。
-
什么是集成開發(fā)環(huán)境呢?
-
集成開發(fā)環(huán)境(IDE,Integrated Development Environment )是用于提供程序開發(fā)環(huán)境的應(yīng)用程序,一般包括代碼編輯器、編譯器、調(diào)試器和圖形用戶界面等工具。
-
像vscode就是一種編輯器,它不是集成開發(fā)環(huán)境,但是它可以添加許多的插件來編輯代各種形式的代碼。
-
像vs2022就是一種集成開發(fā)環(huán)境,在平時使用很方便,但是存儲空間比較大,畢竟有好有缺點嘛,不能兩者兼容。
-
但是我本人不太推薦使用那種上古編譯器比如VC++,DEV++…
接下來我們就開始正式寫第一個C語言程序
- 進入官網(wǎng)下載VS2022,不要去別的地方下載那些盜版的?。。↑c擊進入官網(wǎng)
- 點擊個人免費下載,學(xué)習(xí)下載這個完全夠用了。
- 打開下載
- 打開軟件,創(chuàng)建一個新項目
- 在C語言的學(xué)習(xí)中,大多數(shù)人的第一個程序就是
hello word!
,那么我們怎么打印出hello word
,開始我們學(xué)習(xí)編程之旅,下面就跟著我來一起學(xué)習(xí)。
- 我們知道,C語言所有的字符,符號,都是英文的。
- C語言中代碼是從
main
函數(shù)的第一行開始的。 - main函數(shù)是程序的入口,一個工程中
main
函數(shù)有且只有一個。 - 其中代碼中的
printf
是編譯器的頭文件引入的,可以直接使用。 -
<stido.h>
是頭文件,后綴為.c
是源文件,后綴.h
為頭文件。
#include<stdio.h>
int main()
{
printf("hello world!\n");
return 0;
}
- 有人可能看到我這里寫的是
int main(){ ... return 0}
,通常就是這樣寫的,也是最普遍的寫法
還有一種就是void main(){ },這種寫法比較古老,現(xiàn)在不會使用這種寫法。
三、數(shù)據(jù)類型
寫出了我們的第一個C語言程序,接下來我們來說一說C語言中的數(shù)據(jù)類型
在了解數(shù)據(jù)類型前,我們先探究為什么要寫程序?
- 是為了用程序解決生活中的一些問題。在現(xiàn)實生活中,我們的各種數(shù)據(jù)有很多不同的類型,為了更加豐富的表達生活中的各種值,所以在C語言程序中設(shè)置這么多數(shù)據(jù)類型。
char //字符數(shù)據(jù)類型
short //短整型
int //整形
long //長整型
long long //更長的整形
float //單精度浮點數(shù)
double //雙精度浮點數(shù)
-
每種類型的字節(jié)大小是多少?
下圖所顯示的就是:
計算機中常見的單位:bit(比特),byte(字節(jié)),KB,MB,GB,TB,PB。
- 他們的單位換算為:
1 byte = 8 bit
1 KB = 1024 byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
1 PB = 1024 TB
四、變量,常量
在生活中有些值是不變的(比如:圓周率,性別,身份證號碼,血型等等),有些值是可變的(比如:年齡,體重,薪資等等),引入了變量和常量的概念。
首先,先講述一下變量:
1、變量
語法形式為:type + name。代碼如下:
int age = 150;
float weight = 45.5f; //浮點數(shù)默認為雙精度浮點數(shù),在后面加個f,說明是單精度浮點數(shù)類型
char ch = 'w';
1.1 變量的命名
- 只能由字母(包括大小寫),數(shù)字,下劃線組成。
- 不能以數(shù)字開頭。
- 長度不能超過63個字符。
- C語言是區(qū)分大小寫的。
- 變量名字不能以
關(guān)鍵字
命名字。 - 變量的名字盡量有意義。
1.2 變量的分類
變量分為局部變量和全局變量
#include <stdio.h>
int global = 2019;//全局變量
int main()
{
int local = 2018;//局部變量
//下面定義的global會不會有問題?
int global = 2020;//局部變量
printf("global = %d\n", global);
return 0;
}
總結(jié):
上面的局部變量
global
變量的定義其實沒有什么問題的!
當局部變量和全局變量同名的時候,局部變量
優(yōu)先使用。
1.3 變量的使用
了解了什么是變量,現(xiàn)在我們就要具體地去使用這個變量了,讓我們一起來看看
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("輸入兩個操作數(shù):>");
scanf("%d %d", &num1, &num2);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
在vs編譯時會發(fā)現(xiàn),我們在這里會出現(xiàn)4996警告
。
- 為什么會出現(xiàn)這個警告呢?
是因為在vs中輸入函數(shù),微軟有自己的定義scanf_s,而用scanf函數(shù)不安全。
如何消除這個警告呢?
- 第一種方法就是把
scanf()
改成scanf_s()
,scanf()
也是vs提供的,這種方式很簡單,但是代碼的跨平臺,可移植性就變差了,不推薦這種方法。 - 第二種方法就是在
.c
文件中添加#pragma warning(disable:4996)
這樣就不會提示這個告警了。 - 跟著下圖一步一步的操作
- 首先下載everthing軟件,下載好點擊打開
- 搜索
newc++file.cpp
,打開文件
- 把這行粘貼進去
#define _CRT_SECURE_NO_WARNINGS 1
,后面還要加上個【1】不要忘了
- 這種方法一勞永逸,可以很好的解決我們的問題~~
再次創(chuàng)建一個.c
文件,可以看到自動就有那一行了
1.4 變量的作用域和生命周期
清楚了如果使用變量去編寫程序,接下來我們來看一下變量的作用域和生命周期
作用域:
作用域(scope)是程序設(shè)計概念,通常來說,一段程序代碼中所用到的名字并不總是有效/可用的通常來說,一段代碼中所用到的變量名并不總是有效的,而限定這個名字的可用性的代碼范圍就是這個變量名的作用域。
了解了其基本概念,我們就到代碼中來演示一下
- 可以看到程序報錯了,說【未定義標識符】,可以看出這個作用域具有限定范圍的
int main()
{
{
int a = 10;
printf("a = %d", a);
}
printf("a = %d", a);
return 0;
}
- 以上的話就是局部變量的作用域
- 從下面代碼可以看出,完全沒有報出錯誤,因為對于全局變量的作用域,是從定義變量開始到整個程序運行結(jié)束,整個變量才會被銷毀,而這個變量a,則是在這個代碼塊結(jié)束之后便會銷毀,所以我們在后面才訪問不到這個變量
- 對于全局變量的作用域,還可以這樣使用,把這個b變量定義在add.c這個文件下,然后我們在
test.c
這個文件定義一下這個變量b,用這個extern
聲明一下即可
生命周期:
變量的生命周期指的是變量的創(chuàng)建到變量的銷毀之間的一個時間段
局部變量的生命周期是:進入作用域生命周期開始,出作用域生命周期結(jié)束。
全局變量的生命周期是:整個程序的生命周期
講完了變量,接下去我們來講講常量
2、變量
C語言中常量分為一下幾種:
- 字面常量
-
const
修飾的常變量 - #define 定義的標識符常量
- 枚舉常量
#include <stdio.h>
//舉例
enum Sex
{
MALE,
FEMALE,
SECRET
};
//括號中的MALE,FEMALE,SECRET是枚舉常量
//#define的標識符常量 演示
#define MAX 100
int main()
{
//字面常量演示
3.14;//字面常量
1000;//字面常量
//const 修飾的常變量
const float pai = 3.14f; //這里的pai是const修飾的常變量
pai = 5.14;//是不能直接修改的!
printf("max = %d\n", MAX);
//枚舉常量演示
printf("%d\n", MALE);//0
printf("%d\n", FEMALE);//1
printf("%d\n", SECRET);//2
//注:枚舉常量的默認是從0開始,依次向下遞增1的
return 0;
}
常量就是不變的量,所以叫常量
五、字符串
1. 概念
- 在講字符串之前,我們先來看看下面這個,因為在計算機中存儲、表示的都是二進制,所以我們打印出來的也會是一個二進制
- 首先定義一個char類型的字符變量ch,然后分別以%c、%d、%s去打印出來,可以看到,顯示的結(jié)果各不相同
- %c打印的就是一個字符,%d打印的則是這個字符在ASCLL碼表中的值,最后的%s,打印的就是ch這個字符串
- 然后開始講一講字符串
概念:雙引號引起的一串字符叫做字符串
2. 求解字符串的長度【strlen】
說完了字符串了基本概念,了解了什么是字符串,接下去我們來看看如何入求解字符串的長度
- 對于字符串,大家要知道,結(jié)束標志是一個 \0 的轉(zhuǎn)義字符,轉(zhuǎn)義字符我們下個模塊就講到,這個
\0
表示這個字符串已經(jīng)結(jié)束了。但是在計算字符串長度的時候,這個\0
是不計算在內(nèi)的 - 也是說,求字符串的長度統(tǒng)計的是字符串中
\0
之前出現(xiàn)多少個字
那我們?nèi)绾稳デ蠼庖粋€字符串的長度呢?
- 這里我們需要使用到一個【string.h】頭文件里的一個函數(shù),叫做
strlen()
,可以計算一個字符串的長度,也就是\0之前的長度,這個函數(shù)我們后面會細講
printf("len = %d\n", strlen("abc"));
前面我們說到過char類型可以定義一個字符變量,不僅如此,在這里,我們還可以定義一個字符數(shù)組,什么是字符數(shù)組呢?就是這個數(shù)組中存放的都是字符,我們來看一個具體的定義
char arr[] = "abcdef";
- 以上就是字符數(shù)組的基本定義
- 接著我們再來看一種,下面這一種也是字符數(shù)組的定義方式
char arr2[] = { 'a','b','c','d','e','f' };
- 可以看到,這兩個字符數(shù)組中的內(nèi)容是一樣,那他們打印出來,以及計算出來的長度是否是一樣的呢,我們一起來看一下
- 很明顯,從以上結(jié)果來看,是不一樣的,這是為什么呢?我們通過一張圖示來了解一下
- 從以上這張圖我們應(yīng)該可以很明顯地看出來,為什么第二個arr2數(shù)組在打印的時候會出現(xiàn)【燙燙燙】這種東西呢,如果你自己去編譯器里試試的話應(yīng)該也是這樣
- 因為第二個數(shù)組的內(nèi)容值給到了’f’,并不是一個完整的字符串,但是第一個數(shù)組給到的卻是一個完整的字符串,所以自動擁有一個’\0’,第二個數(shù)組就沒了,所以后面打印出來的只會是一個隨機值,然后直至碰到一個\0為止,遍歷才會結(jié)束
- 所以我們可以看到這個長度也是受到了影響,arr1數(shù)組的長度就是6,但是arr2數(shù)組的長度卻是加上了一些隨機字符后的長度,這就顯得不準確了
3. 轉(zhuǎn)義字符【含筆試題】
- 那什么叫做轉(zhuǎn)義字符呢?我們通過代碼來看看
int main()
{
printf("abcndef");
printf("abc\ndef");
}
- 通過運行結(jié)果我們可以看到,這個
n
,若是在其前面加上了一個\
,則它的意思就發(fā)生了變化,在轉(zhuǎn)義字符里面就叫做【\n換行】,所以可以看到打印到【abc】就發(fā)生了換行,在后一行打印了def
- 然后我們再來看到一個打印一個test.c的路徑
- 從運行結(jié)果來看,并沒有真正地打印出來一個路徑,而是出現(xiàn)了很多空格
- 細心的小伙伴應(yīng)該可以發(fā)現(xiàn)這個test的第一個字符t和路徑的\是同一個顏色,都淡化了,在轉(zhuǎn)義字符里,這個叫做【\t水平制表符】,也及時們鍵盤上的【Tab鍵】,敲一下就能空出4個空格
- 所以我們在printf輸出一個東西的時候,不要去寫一些轉(zhuǎn)義字符,那C語言中有哪些轉(zhuǎn)義字符呢,我們一起來看一下
用一個表格給大家呈現(xiàn):
轉(zhuǎn)義字符 | 釋義 |
---|---|
? | 在書寫連續(xù)多個問號時使用,防止他們被解析成三字母詞 |
\ ’ | 用于表示字符常量 |
\“ | 用于表示一個字符串內(nèi)部的雙引號 |
\ \ | 用于表示一個反斜杠,防止它被解釋為一個轉(zhuǎn)義序列符 |
\a | 警告字符,蜂鳴 |
\b | 退格符 |
\f | 進紙符 |
\n | 換行 |
\r | 回車 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1~3個八進制的數(shù)字。如:\130X |
\xdd | dd表示2個十六進制數(shù)字。 如:\x30 0 |
我們挑重點的說一下
- 首先是二三兩個,看第一行代碼,若你printf的是一個【‘’‘】,那么編譯器就會報錯,你本是想打印一個【’】,這個時候該怎么辦呢,你只需要在前面加上一個\,這就變成了一個轉(zhuǎn)義字符,然后就可以像運行結(jié)果一樣輸出了
- 然后第三個也是同理,這里便不做過多詳解
- 然后就是剛才我們所說的打印路徑,要怎樣才能打印出這個路徑呢?沒錯,只需要再添加一個【\】就可以了,這就表示一個反斜杠,我們到代碼里看一下
- 可以看到,這個路徑已經(jīng)被完全打印出來了
- 最后,我們再來講一下最后兩個有關(guān)八進制和十六進制的
- 一樣,先給出運行結(jié)果
-
有關(guān)【\ddd】,表示的就是八進制,也就是通過八進制去計算,如果用%d打印出來的就是計算的結(jié)果,如果使用%c打印出來的就是這個數(shù)字所對應(yīng)的ASCLL碼符號
-
對于十六進制也是同理,/xdd值就是十進制,然后看上面的打印也是同理
-
對于【\x3a】的話就是用a*160
-
然后我們來說一道有關(guān)轉(zhuǎn)義字符的筆試題
printf("%d\n", strlen("c:\test\628\test.c"));
- 這個結(jié)果是什么呢?答案不盡相同
- 而真正的答案是【14】,為什么呢?我們來看一下
分析
- 首先第一步,我們剛學(xué)了轉(zhuǎn)義字符,【\t】表示的一定是一個字符,所以18排除
- 然后第二步,相信大家最疑惑的就是這個\628,這其實就是我們上面所說的\ddd,但是這都能算嗎?這個時候你就要去想,八進制能包含8嗎,八進制就是0~7的數(shù)字,所以是不會有8,因此這個【\62】算一個轉(zhuǎn)義字符
- 最后我們就可以得出答案為【14】
六、注釋
首先我們要先了解一下注釋是什么,它可以用來干嘛
- 注釋可以將你不需要或者還不想刪除地代碼暫時屏蔽起來,在程序執(zhí)行的時候會直接跳過注釋的代碼,不會運行
- 如果在一些程序中有一些晦澀難懂的代碼,可能你寫出來的代碼需要需要一些批注后面在閱讀你代碼的人才能知道這段代碼是什么意思,這個時候你就可以在這段代碼的上方或是下方寫一些注釋,這樣后人就可以看懂你寫的代碼
int main()
{
//下面是創(chuàng)建一個整型變量并賦值10
int a = 10;
int b = 100;
//C++ 注釋風格 - C99
/* C語言的注釋風格
int c = 10;
int d = 20;
printf("ff");
*/ // - 嵌套的話此處結(jié)束注釋
//不支持嵌套注釋
return 0;
}
- 我們來分析一下,對于雙斜杠//,這個是C99中對于C++的注釋風格,那C語言的注釋風格是怎樣的呢,就是
/**/
- 但是后面我還補充了一句話,就是對于C語言的這種注釋方法,不可以產(chǎn)生嵌套的,例如說這里若是在外層加上一個/**/,這樣return 0;不會被注釋了,為什么呢?因為上面的
/*
和return 0;
上面的那個先匹配了,所以就不會到下面的
七、選擇語句
- 在C語言或是其他編程語言中,都有著三種結(jié)構(gòu)方式:【順序】、【選擇】和【循環(huán)】
- 那這個選擇語句是什么呢?就是你有時候會面臨兩種或多種選擇,不同的選擇對應(yīng)的就是不同的結(jié)果
具體我們通過代碼來看一下
int main()
{
int input = 0;
printf("你要好好學(xué)習(xí)嗎(1/0)\n");
scanf("%d", &input);
if (input == 1)
{
printf("拿一個好offer\n");
}
else
{
printf("回家種田\n");
}
return 0;
}
- 上面這一段代碼,就是一個選擇語句,你可以在終端輸入你的選擇,問你要不要好好學(xué)習(xí)。若你選擇的是1好好學(xué)習(xí),那么你就可以拿一個好offer;但若是你選擇0擺爛,那么就只能回家種田
八、循環(huán)語句
然后我們再來說說另一種形式,也就是循環(huán)語句
- 什么是循環(huán)呢?循環(huán)就是你一直不斷重復(fù)地做一件事,直到某個條件滿足時才會退出
然后我們通過一段代碼再來看一下
int main()
{
int line = 0;
printf("好好學(xué)習(xí)\n");
while (line < 20000)
{
printf("寫代碼:%d\n", line);
line++;
}
if (line == 20000)
printf("好offer\n");
return 0;
}
- 然后對于循環(huán)的話,不僅僅是有
while
,還有do…while()
,for
這些,我們在后續(xù)都會講到
九、函數(shù)
函數(shù)其實就是將一個功能單獨封裝成為一個模塊,然后這個模塊可以被多次調(diào)用,以便來實現(xiàn)代碼的簡化
- 我們先來看這么一段代碼
- 這是一段兩數(shù)求和的代碼,輸入兩個數(shù)據(jù),然后輸出它們的和
- 但是設(shè)想,若是我們要再求另外兩個數(shù)的和,那么就要再次輸入,然后求和的代碼就要再寫一遍,這就徒增了代碼量,顯得整個程序很冗余,那要怎么簡化呢?對就是使用函數(shù)。
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("請輸入兩個操作數(shù)字:>");
scanf("%d %d", &num1, &num2);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
- 我們來看一下使用函數(shù)簡化完之后是什么樣子
- 這段代碼使用了三次求和,得到了三個求和結(jié)果
int Add(int m, int n)
{
return (m + n);
}
int main()
{
int sum1 = 0;
int sum2 = 0;
int sum3 = 0;
sum1 = Add(1, 2);
sum2 = Add(3, 4);
sum3 = Add(5, 6);
printf("sum1 = %d\n", sum1);
printf("sum2 = %d\n", sum2);
printf("sum3 = %d\n", sum3);
return 0;
}
十、數(shù)組
1、數(shù)組的定義
- 首先我們知道數(shù)字這個概念,但是當我們需要一堆的數(shù)字,那么這個數(shù)字存到哪里去呢?沒錯,也就是用一個叫【數(shù)組】的東西存放起來
- 那要怎么存放呢,我們來看一下
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
- 首先需要先聲明這個數(shù)組是什么類型的,是整型、字符型還是浮點型等,數(shù)組的話這些數(shù)據(jù)都是可以存儲的,然后在一個變量后面加上一個
[]
,括號里可以寫上你準備為這個數(shù)組開辟多大的空間,比如說上面寫的是10,那么這個數(shù)組中最多能存下的數(shù)據(jù)也就只有10個,但是若你不寫的話,就可以存多個,后面會教大家一個方法去計算沒有給出數(shù)據(jù)具體大小如何去求這個數(shù)組的大小 - 這里先給出,大家可以先看看,sizeof()是一種單目操作符,是用來計算你所使用的操作數(shù)所占的空間字節(jié)大小
int sz = sizeof(a)/sizeof(a[0]);
- 剛才說過,數(shù)組除了可以存放整數(shù)數(shù)據(jù)外,還可以存放字符型、浮點型的數(shù)據(jù)
char b[] = { 'a','b','c'};
double c[] = {2.5,6.9,7.7,1.5 }
2、數(shù)組的下標
知道了數(shù)組怎么聲明,那我們聲明的這些數(shù)組怎么獲取到呢?
- C語言規(guī)定:數(shù)組的每個元素都有一個下標,下標是從0開始的訪問。下面就是我們通過
下標
去訪問的a數(shù)組中下標為8的元素,打印出來的就會是9
//下標訪問數(shù)組元素
printf("%d\n", a[8]);
-
具體大家看圖示就能一目了然了
-
可以看到,這里arr數(shù)組的大小是10,那我們?nèi)ピL問18這下標會怎么樣呢,去編譯器里看看
-
從圖中可以看出,總共下標也就只有9,你訪問到了,那就會產(chǎn)生越界訪問,那么你訪問到的就會是一個隨機值
3、數(shù)組的使用
- 看一下代碼。我們首先定義了一個大小而10的整型數(shù)組,然后將其內(nèi)容初始化為0,然后我們通過一個在while循環(huán)中通過scanf去輸入一些數(shù)據(jù),將其一一地通過下標放入數(shù)組中。然后呢,還是一樣,通過循環(huán)去遍歷這個數(shù)組,調(diào)用printf去打印出里面的數(shù)據(jù)
- 這就是數(shù)組的一種使用方法,其余的我們放到后面數(shù)組章節(jié)細講
int main()
{
int arr[10] = { 0 };
//0 ~ 9 - 輸入10個值給數(shù)組
int i = 0;
while (i < 10)
{
scanf("%d", &arr[i]);
i++;
}
i = 0;
while (i < 10)
{
printf("%d ", arr[i]);
i++;
}
return 0;
}
十一、操作符
C語言中操作符不少,這里我們做簡要介紹,后續(xù)會詳細講解
1、算數(shù)運算符
- 這里我們重點來講講【除】和【取余】
- 首先來看這段代碼,結(jié)果會是多少?
int a = 7 / 2;
printf("%d\n", a);
- 運行結(jié)果是3,因為運算符的左右兩邊都是整數(shù),所以執(zhí)行的是整數(shù)除法,包括下面這段也是一樣,運行結(jié)果都是3,只是因為float浮點數(shù)的原因,小數(shù)點后多出6個0
float f = 7 / 2;
printf("%f\n", f);
- 那怎么將其變?yōu)楦↑c數(shù)除法,也就是得到3.5這個答案,你只需要將7或2任意一個數(shù)字改為浮點數(shù)即可,例如說7.0/2.0,至少有一個操作數(shù)是浮點數(shù)執(zhí)行的才是浮點數(shù)除法
我們來看看結(jié)果
- 然后我們再來看看【取余】操作符
int main()
{
// % 取余操作符,關(guān)注的是除法后的余數(shù)
int a = 7 % 2; //商3余1
printf("%d\n", a);
return 0;
}
- 取到就是一個整數(shù)對另一個整數(shù)做除法后的余數(shù)
2、移位操作符
- 這一塊大家先了解一下,先不做細講,會在操作符章節(jié)細講
左移就是擴大
右移就是縮小
3、位操作符
-
上面叫移位,這里叫位,區(qū)別大嗎?區(qū)別可大了,完全是兩個概念
-
這里也會在后面章節(jié)詳解
4、賦值操作符
- 有關(guān)賦值運算符,第一個大家應(yīng)該不陌生,就是我們常見的賦值運算,后面呢則是一些【加減乘除取余移位】這些復(fù)合而成的,你可以到編譯器里自己試試看
5、單目操作符
重點來說一下單目運算法
- 首先是這個取反操作,在C語言中呢,表示真假只有兩種,用0表示假,用
非0
表示真 - 所以看下面的代碼,這個a就是【真】,所以會執(zhí)行“haha”語句,但若是你把a換成0,那么
!a
就是【真】,就會打印“hehe”語句
//C語言是如何表示真假的呢?
//0表示假,非0表示真
//-1 表示的就是真
int main()
{
//把假變成真,把真變成假
int a = 10;
if (a)
printf("haha\n");
if(!a) //這個不執(zhí)行
printf("hehe\n");
return 0;
}
- 然后【取正】【取負】很簡單,看到下面代碼,會打印a的相反數(shù)
int a = -10;
printf("%d\n", +a);
printf("%d\n", -a);
- 然后對于取地址和星號運算符,我們在下面指針的部分介紹
- 然后來看看sizeof()這個運算符,sizeof()是一個函數(shù)嗎?不是的,
sizeof
是一個操作符
int a = 10;
char c = 'w';
int arr[10] = { 0 };
printf("%d\n", sizeof(a)); //4
printf("%d\n", sizeof(c)); //1
printf("%d\n", sizeof(arr)); //40
- 對于sizeof()這個運算符呢,它是用來計算所占內(nèi)存空間的大小,單位是字節(jié),所以上面代碼的輸出分別為整型、字符型和一個數(shù)組所占內(nèi)存空間的大小
- 因為這些變量都是用int、char這些變量類型定義出來的,所以可以直接用sizeof()傳入這些變量的類型,出來的結(jié)果也是一樣的
printf("%d\n", sizeof(a)); //4
printf("%d\n", sizeof(int)); //4
printf("%d\n", sizeof(c)); //1
printf("%d\n", sizeof(char)); //1
- 既然這是一個操作符,那干嘛要這個括號呢?直接去掉不就好了,不然引起歧義,就像下面這樣
printf("%d\n", sizeof int);
- 我們在編譯器上跑一下可以看到,是不能運行的~~
- 這其實就更好地可以說明sizeof是一個操作符,不是函數(shù),括號可以省略
- 然后我們就可以得出結(jié)論:變量可去括號,類型不可取去括號
上面我們有提到過,當我們沒有對一個數(shù)組設(shè)定初始化元素個數(shù)時,可以使用sizeof()去計算這個數(shù)組中有多少元素
- 就是下面這樣,sizeof(arr)就是整個數(shù)組的大小,sizeof(arr[0])便是一個元素的大小,當然你也可以寫成【sizeof(int)】,因為整型數(shù)組中一個元素的大小一定是4個字節(jié),也就是int所占的字節(jié)大小
printf("%d\n", sizeof(arr));;
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
然后我們來說一下 【前置、后置–】與【 前置、后置++】
- 這兩個其實是一樣的,我們先來看一下【 前置、后置++】
- 對于前置++的話就是先++在賦值,所以下面的a會把++完之后的值給到b,然后自己也會++,因此最后輸出的便是11 11
int a = 10;
int b = ++a; //先++后賦值
// a = a + 1
// b = a
printf("%d %d\n", a, b); //11 11
- 對于后置++就不一樣了,剛好相反,就是c會先把自己的值給到d,然后自己再++,所以d得到的就是10,c后面++完后之后就是11
int c = 10;
int d = c++; //先賦值后++
// d = c;
// c = c + 1
printf("%d %d\n", c, d); //11 10
- 然后我們來說【前置、后置–】,同理
int a = 10;
int b = --a; ///先--在賦值
printf("%d %d\n", a, b); //9 9
int c = 10;
int d = c--; ///先賦值后--
printf("%d %d\n", c, d); //9 10
- 然后這一段也是一樣,首先打印a–的一定是之前的值,然后打印的就是–之后的值,也就是9
int a = 10;
printf("%d\n", a--); //先使用,后--
printf("%d\n", a);
對于前置、后置的±,老是喜歡出一些面試題,把你搞暈,其實根本沒什么意義,我們來看看
int a = 1;
int b = (++a) + (++a) + (++a);
printf("%d\n", b);
-
從VS來看,這段代碼的運行結(jié)果是12,但是在Linux的gcc編譯器中,運行結(jié)果竟然是10
-
一段代碼在不同編譯器運行結(jié)果不同,說明這段代碼其實有問題的,準確的說是存在歧義的
-
我們來講單目操作符的最后一個,強制類型轉(zhuǎn)換
-
首先來看這兩句代碼,你認為這會輸出什么
int a = 3.14;
printf("%d\n", a);
- 因為3.14給到了一個整型變量a,所以只會保留整數(shù),這個時候大家看下面我用紅筆畫起來的一段Warning,說這個【從“double”轉(zhuǎn)換到“int”】,可能會丟失數(shù)據(jù)
- 這個時候應(yīng)該怎么辦呢?你可以在3.14前面加上一個(int),將這個數(shù)強制轉(zhuǎn)換成整型,也就是我上面注釋掉的一行代碼,這個時候你再去運行試試,就不會報出Warning了
6、關(guān)系操作符
- 對于前面的四個,直接用就可以了,和直觀地進行一個比較。我們來講一下后面的兩個
- 也就是比較兩個數(shù)是否相等與不等,這個要與【賦值運算符】中的【=】做區(qū)別,一個是比較兩個數(shù)或是變量的,另一個則是進行賦值運算的,不混淆了
int a = 10;
int b = 20;
if (a == b)
printf("haha\n");
if(a != b)
printf("hehe\n");
- 那這個時候就有同學(xué)問了,除了這個數(shù)字的比較,可以比較字符串嗎,我們來看看
char arr1[] = "abcdef";
char arr2[] = "abcdef";
if (arr1 == arr2)
printf("==\n");
else
printf("!=\n");
- 可以看到,兩個字符數(shù)組明明是一樣的,但是卻走了第二個分支,打印了【!=】,這里其實就出問題了。為什么呢?這個我們后面會說到,數(shù)組名是整個數(shù)組的首元素地址,其實【==】比較的是它們的地址
- 對于字符串的比較,在C語言中有專門的函數(shù),叫做strcmp(),它和strlen()一樣都是屬于【string.h】頭文件里的,若比較的兩者相等的話,則會返回0,前者大于后者,返回 > 0的數(shù),后者大于前置,返回 < 0的數(shù),所以只需要去判斷一下去和0的大小即可
//兩個字符串不可以用“==”來判斷是否相等,使用strcmp(庫函數(shù))
char arr1[] = "abcdef";
char arr2[] = "abcdef";
if (strcmp(arr1,arr2) == 0)
printf("==\n");
else
printf("!=\n");
這樣的話結(jié)果就正確了
7、邏輯操作符
- 邏輯與【&&】是并且的意思,邏輯或【| |】是或者的意思。為真則為1,為假則為0
- 對于邏輯與,只有兩個數(shù)均為1是才為1,只要有一個為0,結(jié)果即為0
int a = 5;
int b = 4;
int c = a && b;
printf("c = %d\n", c);
if (a && b)
printf("hehe\n");
- 從上述代碼和運行結(jié)果可以看出,因為a,b都不是0,因此它們的結(jié)果為1,才可以進入下面那個if判斷,若是把a,b其中任意一個改為0,則結(jié)果便為0,然后不會進入下面的這個判斷
- 對于邏輯或的話,只要其中有一個為1,則為1,只有兩個數(shù)均為0是,才為0
- 所以下面的顯示結(jié)果是0,并且沒有進入這個if條件的判斷
int a = 0;
int b = 0;
int c = a && b;
printf("c = %d\n", c);
if (a || b)
printf("hehe\n");
8、條件操作符
- 下面是一段簡單的if分支判斷,然后給b賦值
int a = 10;
int b = 0;
if (a > 5)
b = 3;
else
b = -3;
printf("b = %d\n", b);
- 但是對于三目運算符來說,不用這么麻煩,只需要這么一句就好了
- 具體意思就是,判斷a是否大于5,若是,則將b賦值為3,若不是,則將b賦值為-3
a > 5 ? b = 3 : b = -3;
- 但是其還有更簡便的寫法,也是一樣去判斷,最后把得出來的值給到左邊的b即可
b = (a > 5 ? 3 : -3);
9、逗號表達式
我們先來說一下其運算規(guī)則:從左向右依次計算,整個表達式的結(jié)果是最后一個表示式的結(jié)果
- 列舉了一個逗號表達式,大家可以去自己試著計算一下,每過一個表達式參與運算的變量都會改變,最后看打印出的a,b,c的值,也是發(fā)生了變化
int a = 3;
int b = 5;
int c = 0;
int d = (a += 2, b = b - c + a, c = a + b);
//a = 5 b = 10 c = 5 + 10 = 15
printf("d = %d\n", d);
printf("%d %d %d\n", a, b, c);
10、其他
【下標引用操作符】
- 什么是下標引用操作符呢?也就是這個
[ ]
,我們在定義數(shù)組的時候指定的數(shù)組大小
int arr[10] = { 0 };
arr[4] = 5;
printf("%d\n", arr[4]);
- 對于上面這段代碼,我們稱arr4 是 [ ]的兩個操作符
- 我們回憶一下【+】運算符,這是一個雙目運算符,比如說2 + 3,那么就可以稱2 3 是 +的兩個操作符,對于我們來說2 + 3可以寫成3 + 2,既然雙目運算符可以這么交換著來做,那【下標引用操作符】可以嗎,答案是可以的?。?!
- 上面這段代碼,我們還可以寫成這樣
int arr[10] = { 0 };
4[arr] = 5;
printf("%d\n", 4[arr]);
接下來的話是這個叫【函數(shù)調(diào)用】的操作符
int Add(int x, int y)
{
return (x + y);
}
int main()
{
int c = Add(2, 3); //()是函數(shù)調(diào)用操作符,操作數(shù)是:Add 2 3
printf("c = %d\n", c);
return 0;
}
- 很明確,就是函數(shù)外面的兩個小括號,這個我們在上面說到sizeof()操作符時也提到過,對于sizeof(),雖然其有(),但是不可以把它認為是一個函數(shù),它也會是一個操作符
- 然后對于函數(shù)調(diào)用操作符的話,看到上面的Add函數(shù),()是操作符,那么操作數(shù)就是Add 2 3
十二、常見關(guān)鍵字
1、前言
了解了C語言中的常見運算符,接下來我們來看看C語言中的關(guān)鍵字
-
首先對于關(guān)鍵字,我們要注意的兩點是
1、關(guān)鍵字是直接使用的,我們得了解
2、變量名不能是關(guān)鍵字 -
從下面這些可以看出,在C語言中,關(guān)鍵字還是蠻多的
- 首先單獨說一下【auto】,它比較特殊,因為在編譯器中,當你定義一個變量的時候默認就是存在的
- auto,翻譯過來就是自動的,在C語言里指得是自動變量,所有你定義的局部變量都是自動創(chuàng)建、自動銷毀的,所以局部變量都是auto修飾的
- 就像下面這個整型變量a,你在int的前面加上或是不加auto 都是不會報錯的, 原因就是所有局部變量都是auto
//auto int a = 10;
int a = 10; //auto可以省略
2、有關(guān)數(shù)據(jù)存儲的底層原理
- 有關(guān)寄存器這個東西,涉及到了數(shù)據(jù)存儲,我們來詳細說一下,讓大家先了解一下這個底層原理
首先你要知道在計算機中的數(shù)據(jù)是存放在哪里的
①內(nèi)存 ②硬盤 ③高速緩存 ④寄存器
然后我們再通過這張圖來了解一下
-
對于計算機中的寄存器,其實它所空間是很小的,單位只有字節(jié),但是它的讀寫速度非???,可以直接與CPU【中央處理器】進行交互
-
然后越往下這個空間越大,內(nèi)存的話現(xiàn)在普遍都是8G,16G這樣,大一點有32G,不會像很早之前的只有2MB這樣;對于硬盤的話,我們?nèi)ナ袌錾腺I也是500G,1個T這樣的大小
-
我們的寄存器,因為它的讀取速度很快,因此CPU直接到寄存器里面拿數(shù)據(jù),但這個時候寄存器內(nèi)存不夠大了怎么辦呢?裝不過這么多,這個時候我們所知道的高速緩存,也就是Cache,會給寄存器提供內(nèi)存,那高速緩存里又不夠了,這個時候就繼續(xù)讓內(nèi)存給它提供。這樣的話整體地提高了計算機的運行效率
-
下面就是【register】這個關(guān)鍵字的用法,在定義這個變量b的時候加上了這個關(guān)鍵字,就是【建議】編譯器把這個變量放到寄存器中,這里要注意,只是建議,而不是直接放入
-
具體再如何使用大家可以去查閱一些資料,這里不做過多詳解
//建議把b放到寄存器中
register int b = 10;
3、typedef關(guān)鍵字
首先就是這個【typedef】,這個關(guān)鍵字的話是用來重命名的,用在結(jié)構(gòu)體上會比較多
typedef struct Linknode{
int data[MaxSize];
struct Linknode* next;
}LNode;
- 當然它不止應(yīng)用在結(jié)構(gòu)體上,對于一些數(shù)據(jù)類型也是可以重命名的,例如下面這個【unsigned int】,后面你在使用【uint】定義變量的時候就和【unsigned int】一樣
typedef unsigned int uint;
int main()
{
unsigned int num1 = 0;
uint num2 = 0; //與num1一樣
return 0;
}
4、static關(guān)鍵字
最后再來說一下這個static關(guān)鍵字
- 這里是來說說C語言中的static關(guān)鍵字,首先你要了解static關(guān)鍵字可以用來修飾什么,它主要是可以用來修飾下面三個
- 修飾局部變量
- 修飾全局變量
- 修飾函數(shù)
4.1、static關(guān)鍵字修飾局部變量
首先我們來看看static對于局部變量的修飾
void test()
{
int a = 3;
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
- 你認為上面這段程序會輸出什么??吹街鞒绦颍褂脀hile循環(huán)來控制i變量,當i = 10的時候邊不會進入循環(huán),所以是會循環(huán)10次,然后看內(nèi)部的test()函數(shù),每次循環(huán)調(diào)用這個函數(shù)的時候都會定義一個變量a,然后++之后變?yōu)?,然后輸出
- 所以這段程序的運行結(jié)果是會輸出10個4
- 然后我們修改一下這個定義的變量a,將其設(shè)置為靜態(tài)變量,也就是在int前面加上一個static修飾
- 那這個時候你認為上面那段程序會打印出什么呢?
static int a = 3;
- 首先你要了解靜態(tài)變量的特性以及其余普通變量之前的區(qū)別
①普通的局部變量是放在內(nèi)存的棧區(qū)上的,進入局部范圍,變量創(chuàng)建,出了局部范圍變量銷毀
②當static修飾局部變量時,局部變量是在靜態(tài)區(qū)開辟空間的,這時的局部變量,出了作用域變量不銷毀,下次進去作用域,使用的是上一次遺留的數(shù)據(jù)(改變了存儲位置,由棧區(qū)–>靜態(tài)區(qū),使得變量的生命周期發(fā)生了變化)
- 知道了這些,你應(yīng)該清楚這個打印結(jié)果是多少了,
4~13
,每一次進入這個test()函數(shù)時,這個變量a將不再被執(zhí)行,也就是只會在第一次進入這個函數(shù)的時候定義,之后就會一直存在,知道這個程序結(jié)束時它才會被銷毀,所以這個變量a每次保留的便是上一次++后的結(jié)果
- 看到了上面的結(jié)果,對于靜態(tài)變量修飾成員相信你也有了一個初步的了解,對于普通的局部變量,是存儲在棧區(qū)上的。但是對于靜態(tài)變量,你知道它是存儲在什么地方的嗎?
- 沒錯,就靜態(tài)區(qū),我們通過下面這張圖再來了解一下在計算機內(nèi)存中變量到底是如何存儲的
4.2、static關(guān)鍵字修飾全局變量
add.c:
int g_val = 2022;
test.c:
extern int g_val; //聲明外部符號
int main()
{
printf("%d\n", g_val);
return 0;
}
- 以上的這種全局變量聲明,以及【extern】關(guān)鍵字調(diào)用,是聲明一個變量,但是若這個g_val變量被定義成了靜態(tài)變量,會怎么樣呢?我們來看看
-
可以看到,這個外部命令無法被解析
全局變量是具有外部鏈接屬性的,如果全局變量被static修飾,外部鏈接屬性就變成了內(nèi)部鏈接屬性,其他源文件就沒法再通過鏈接找到這個符號
-
所以可以得出結(jié)論,static修飾后的局部變量只能在自己所在的.c文件內(nèi)部使用~
4.3、static關(guān)鍵字修飾函數(shù)
- 其實這個理念也是一樣的,若你不使用static修飾,那你可以用extern關(guān)鍵字做一個引入,那它就是一個外部鏈接,但若是你使用static修飾,那么這個函數(shù)就只能本源文件使用,不可以給到外部的文件使用,這就是一個內(nèi)部鏈接了
- 可以看到,也是同理,這是一個內(nèi)部鏈接,外部是訪問不到的,即使是有這個extern關(guān)鍵字
十三、 #define 定義常量和宏
- 首先來說說這個#define去定義常量
#define MAX 100
int main()
{
printf("%d\n", MAX);
int a = MAX;
int arr[MAX] = { 0 };
printf("%d\n", a);
return 0;
}
-
看到如上代碼,我使用#define定義了一個MAX常量,并且其值為100,在main函數(shù)中,你就可以直接使用這個常量,對它進行打印、賦值
-
當然除了定義整型數(shù)據(jù)常量,其他類型也是可以的,例如字符串也可以
#define STR "abcdef"
printf("%s\n", STR);
講完使用#define去定義常量,我們再來說說宏定義,它也是利用#define去聲明的
- 下面有一個求和的函數(shù)以及宏定義求和的寫法
//函數(shù)
int Add(int x, int y)
{
return x + y;
}
//宏
#define ADD(x,y) ((x) + (y)) //為了保持整體性
除了求和的功能外,其實你還可以定義其他功能,例如說比較兩個數(shù)的較大值,就可以像下面這么去寫,使用一個三目運算符即可
#define MAX(x,y) ((x) > (y) ? (x) : (y))
十四、 指針
1、引言
- 對于指針這一塊,很多同學(xué)在剛開始學(xué)習(xí)C語言的時候就聽別人說起過,說指針很難很難,訪問內(nèi)存、取地址這些操作,既危險又難搞
2、內(nèi)存的概念和介紹
-
對于指針這一塊的話,是直接和計算機中的內(nèi)存發(fā)生關(guān)系的,所以我們先來講講內(nèi)存相關(guān)的知識,帶大家先行了解一下底層的知識
-
對于內(nèi)存,大家在日常生活中應(yīng)該也有聽到過,例如我們?yōu)殡娔X、筆記本買的內(nèi)存條,以及我們手機的內(nèi)存,對于這個內(nèi)存來說,一般都是8G或是16個G,與內(nèi)存相對應(yīng)的,那就是硬盤,一般的話都是500G或是1個T這樣
-
在計算機中,內(nèi)存是一塊連續(xù)的存儲空間,但是這樣就無法分配到每一個部分進行使用,這個時候呢就將內(nèi)存分成了一塊塊小的內(nèi)存單元,那為了能夠有效的訪問到內(nèi)存的每個單元,就給內(nèi)存單元進行了編號,這些編號就被稱為該內(nèi)存單元的地址
- 從上面這張圖示,就可以很直觀地看出內(nèi)存在計算機中到底是如何存儲的,每一個內(nèi)存單元的大小都是一個字節(jié),然后為它們都進行了編號,這樣在外界需要訪問時,就可以根據(jù)這個內(nèi)存編號去指定進行一個訪問,這個一個個編號其實就被稱為是地址
知曉了地址的基本概念后,我們再來到編譯器中去看看這個地址究竟是怎樣分部的
- 首先我們來看最簡單的一句代碼,就是定義一個變量a,我們都知道int整型的變量在內(nèi)存中是占4個字節(jié)的,我們在這句代碼上打個斷點進入內(nèi)存窗口一看究竟
int main()
{
int a = 4;
}
- 輸入這個【&a】,就可以看到內(nèi)存中為變量a開辟的4個內(nèi)存單元,首地址就是從【0x00CFF814】開始,整型變量占4個字節(jié),看我框起來的這4個就是,對于每一個字節(jié)它都有自己的一個編號, &a呢就是取到第一個字節(jié)的地址
- 那我們要怎么使用代碼去獲取這個地址呢
&a // 拿到的值第一個字節(jié)的地址
- 我們通過調(diào)試窗口再來看一下。很明顯,得到了我們想要的結(jié)果
- 或者你不想到調(diào)試窗口中去看的話,也是可以的
- 我們直接printf打印出來即可,可以看到,這里使用的是%p,這是專門對于地址訪問的,如果你是%d,出來的就是格式化后的數(shù)字了
- 講完了內(nèi)存,講完了地址,接下去才是真正的指針,但其實對于地址來說,它就是指針,指針是地址的一個別名,下面就來看一下指針是如何去定義的
int a = 4;
int* pa = &a;
- 可以看到,在int類型后我加上了一個【*】星號,這就說明這是一個指針類型的變量,這個pa就是【指針變量】,因為上面說過指針是地址的別名,所以這個等式是成立的,pa這個指針變量可以去接收a的地址,也存放了a的地址
-
既然這個指針變量存放了變量的地址,那么可不可以通過這個指針變量去訪問到這個地址并且把它打印出來呢?答案是可以的,這就是涉及到我們的下一個知識點,就是指針的解引用
-
利用【*】這個操作符
*pa
- 上面定義了,pa就是一個指針變量,*pa其實就是通過pa中存放的地址,找到這個地址所存放的空間,這個時候取到的其實就是變量a,因為取到了這個地址,這塊空間上所存放的起始就是a變量的內(nèi)容,我們通過運行來看一下
小結(jié)
①指針其實就是地址,地址就是內(nèi)存單元的編號
②把地址進行存儲的時候,就可以放到一個變量中,這個變量就是【指針變量】
③我們說的指針,實際上在專業(yè)術(shù)語中叫做【指針變量】
④【*】星號解引用可以通過存放變量的地址快速訪問到那個變量在內(nèi)存中所存放的位置,繼而獲取內(nèi)容
3、指針變量的大小
- 求一個變量的大小就是用
sizeof()
這個關(guān)鍵字
int a = 10;
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(int));
- 上面這段代碼的打印就是4 4,那請問下面這段呢?
int a = 10;
int* pa = &a;
printf("%d\n",sizeof(pa));
printf("%d\n",sizeof(int*));
- 很明顯,也是4 4
- 在編譯器的偏左上角,有一個x64和x86,這個東西叫做【運行環(huán)境】,x64代表你在64位OS的環(huán)境下運行代碼,x86代表的就是32位,剛才我選擇的是32位,現(xiàn)在我把它改成64位,
- 很明顯,一樣的代碼,但是在不同的運行環(huán)境下所產(chǎn)生的值卻不同,
- 指針變量存放的就是地址,所以指針變量的大小取決于存儲一個地址需要多大的空間
要看到不是地址,其實是存儲的地址線,沒錯,就是硬件上的地址線
- 我們所用的電腦,其實就是硬件,是硬件的話就需要通電,那在我們的電腦上其實就存在著這么一種【地址線】,我們上面所說的32位與64位,也可以對應(yīng)到這個地址線中,因為在32位的環(huán)境下,是32根地址線;64位環(huán)境下就是64根地址線
- 當我們是32根地址線時,在通電之后就會有一個電信號,這個電信號就是0/1,那這些電信號具體是怎樣的呢,我們來看一下
- 就是0101這樣的存儲方式,然后根據(jù)二進制的逢二進一去羅列出這32根地址線可以存儲下多少地址,這里告訴你,一共是有232個地址可以存儲
- 那這其實就可以得出結(jié)論了,32個0或者1組成得的地址序列,需要32個bit,也就是4個byte去存放,而這4個字節(jié)也就對應(yīng)著我們指針變量的大小,因此就可以得出為什么指針變量的大小是4個字節(jié)了
- 然后來解釋一下為什么在64位環(huán)境下這個指針變量就變成了8個字節(jié),這其實你自己也可以去推導(dǎo),32個0或1組成的地址序列需要32個比特位,那么這里便需要64個比特位,根據(jù)1B = 8bit,所以就需要8個byte去存放,這也可以得出在64位環(huán)境下指針變量的大小是8個字節(jié)
了解了上面這些,知道了指針變量的大小取決于地址的大小,下面我們來看看這些指針變量的大小是多少,我是在32位環(huán)境下運行的
printf("%d\n", sizeof(short*));
printf("%d\n", sizeof(long*));
printf("%d\n", sizeof(long long*));
printf("%d\n", sizeof(float*));
printf("%d\n", sizeof(double*));
- 是1 4 8 4 8 嗎,如果是這個答案的話請你再回去仔細看一下上面的推導(dǎo)過程
- 我們來看一下運行結(jié)果
-
可以看到,均為4,它們都是指針變量,指針變量求它的大小看的是什么,看到就是地址的大小,上面說了,我是在32位環(huán)境下運行的,因此就是32根地址線,需要32個bit,也就是4個byte去存放
-
可以看到,報了很多Warning,這是為什么呢,明明這個代碼就是可以運行的,而且還可以出結(jié)果這里報了一個【符號不匹配】的問題,為什么呢?這里明確說一下,sizeof()計算數(shù)據(jù)字節(jié)大小的時候默認返回的類型是unsigned int,也就是無符號整型,但%d是用來打印整型變量的,所以這里才會出現(xiàn)【符號不匹配】的問題
- 應(yīng)該將其修改問%zu去打印才對,你只要記住它是專門用來打印sizeof()的返回值的就行了,不行深入了解也沒關(guān)系
- 修改如下,可以看到,已經(jīng)一個Warning都沒有了
十五、結(jié)構(gòu)體
對于結(jié)構(gòu)體,也是C語言中比較重要的一個部分,因為C語言是一門面向過程的語言,它不像C++、Java那樣面向?qū)ο?,具有類,可以在類?nèi)定義成員變量和成員方法,所以C中就有了結(jié)構(gòu)體這一個東西,可以用來描述復(fù)雜對象
- 我們都去書店買過書,知道書它有書名、出版社、作者,這些都可以定義為字符類型,但是還有書的價格,怎么定義呢,難道也定義成字符類型嗎,當然不是,依舊是定義成浮點類型,除了這些,其實還有很多種類需要去定義
- 但是對于這么多的類型,都要分開嗎,這肯定不行,這樣這本書就不是一個整體了,如果你有面向?qū)ο蟮乃季S就知道,它的屬性和行為都是定義在這一個類中,都是封裝好的,這就是類的封裝
- 在C語言中,我們也可以實現(xiàn)封裝,那就是用結(jié)構(gòu)體
我們以學(xué)生類型來做一個封裝
- 可以看到,我們使用到了struct這個關(guān)鍵字,這個就是在關(guān)鍵字那一模塊所屬要留在這里講解的關(guān)鍵字,stu就是student的簡寫。可以看到,里面有著三種類型,分別是姓名、年齡和成績,因為一個學(xué)生都具備這三種屬性,這是他們共同的屬性,所以可以將他們封裝在一起
struct stu {
char name[20]; //姓名
int age; //年齡
float score; //成績
};
- 那對于結(jié)構(gòu)體這種復(fù)合類型怎么去定義變量進行初始化呢,我們來看看
- 其實和普通變量也是一樣的,你要把【struct stu】看做是一個類型,用這個類型定義出來的變量就叫做【結(jié)構(gòu)體變量】,對于每個結(jié)構(gòu)體變量的初始化,都需要使用一對大括號{},里面去一一按照順序去初始化你在結(jié)構(gòu)體中定義的變量
- 溫馨提示:這里的float成績類型后面加上f與double類型作為區(qū)分
struct stu s1 = { "zhangsan",20,80.5f };
struct stu s2 = { "lisi",25,90.5f };
那初始化了這些變量后如何將他們打印出來呢,也就訪問到每一個同學(xué)的信息文章來源:http://www.zghlxwxcb.cn/news/detail-761125.html
- 這里就要使用到【.】點操作符,這個也是我們前面留下的,這個操作符可以去通過結(jié)構(gòu)體聲明出來的變量訪問當前這個變量所具有的信息,代碼如下:
//格式:結(jié)構(gòu)體變量.結(jié)構(gòu)體成員
printf("%s %d %f\n", s1.name, s1.age, s1.score);
printf("%s %d %f\n", s2.name, s2.age, s2.score);
好,初識C語言就到這里結(jié)束了,后面我會對整個C語言的內(nèi)容進行梳理,希望對大家有幫助?。。」餐佑?!文章來源地址http://www.zghlxwxcb.cn/news/detail-761125.html
到了這里,關(guān)于C語言之初識C語言的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!