數(shù)據(jù)類型
基本數(shù)據(jù)類型
- java基本數(shù)據(jù)類型
* byte 1個字節(jié)
* short 2個字節(jié)
* int 4個字節(jié)
* long 8字節(jié)
- 浮點型
* float 4個字節(jié)
* double 8字節(jié)
- 字符型
* char 2字節(jié)
- boolean true/false
C的基本數(shù)據(jù)類型
- 整型
* short int
* int
* long int
* long long int
- 浮點型
* float
* double
- 字符型
* char
格式化輸出
- short類型:
short a = 123;
printf("%hd\n", a);
- int類型
int b = 123;
printf("b = %d\n", b);
- long 類型
long int c = 345;
printf("c = %ld", c);
- long long 類型
long long d = 123456;
printf("d=%lld\n", d);
- float 類型
float e = 1.234;
printf("e=%f\n", e);//默認6位有效數(shù)字
printf("e = %.2f\n", e);//保留兩位有效數(shù)字
- double 類型
double f = 2.34567;
printf("f = %lf\n", f);//默認6位有效數(shù)字
printf("f = %.4lf\n", f);//保留四位有效數(shù)字
- 字符類型
char g = 'a';
printf("g = %c\n", g);
各種數(shù)據(jù)類型在內(nèi)存中的大小
- 判斷變量在內(nèi)存中的大小
int a = 12;
int size = sizeof(a);
printf("sizeof(int) = %d\n", size);
- 基本數(shù)據(jù)類型在內(nèi)存中的大小
sizeof(int) = 4;
sizeof(short) = 2;
sizeof(long) = 4;
sizeof(long long) = 8;
sizeof(float) = 4;
sizeof(double) = 8;
sizeof(char) = 1;
- 0為假, 非零為真。
if(0){//假
}else{
}
指針 直接操作內(nèi)存區(qū)域
- 指針賦值和修改值
int a = 123;
int *p;
p = &a;//將a的地址取出來, 然后賦值給p
printf("a=%d\n",*p);
*p = 234;//將234賦值給指針p
printf("a=%d\n", a);
- 交換兩個數(shù)的值
int a = 0;
int b = -1;
int *p1 = &a;
int *p2 = &b;
*p1 = *p1^*p2;
*p2 = *p1^*p2;
*p1 = *p1^*p2;
printf("a =%d, b = %d\n", a, b);
- 多級指針
void test(){
int a = 1;
int *p1 = &a;//一級指針
int **p2 = &p1;//二級指針
int ***p3 = &p2;//三級指針
int ****p4 = &p3;//四級指針
printf("*p1 = %d\n", *p1);
printf("**p2 = %d\n", **p2);
printf("***p3 = %d\n", ***p3);
printf("****p4 = %d\n", ****p4);
}
- 函數(shù)指針
int add(int a, int b){
return a+b;
}
int minus(int a, int b){
return a-b;
}
//指針當做函數(shù)參數(shù)
int compute(int a, int b, int(*pf)(int, int)){
return pf(a, b);
}
void test2(){
//定義函數(shù)指針變量p,p指向一個函數(shù),
//函數(shù)的返回值必須是int, 函數(shù)的形參
int (*p) (int, int);
p = &add;
p = −
int result = p(2, 3);
//使用方式一
int result = compute(2, 3, p);
//使用方式二
result = compute(2, 3, &add);
printf("result = %d\n", result);
}
- 野指針 沒有任何指向的指針
int *p;
*p = 123;
printf("*p = %d\n", *p);
數(shù)組
- 數(shù)組定義
void test3(){
//數(shù)組定義
int arr1[10];
int arr2[] = {1, 2, 3, 4, 5};
int arr3[10] = {1, 2, 3};
int len1 = sizeof(arr1)/sizeof(int);
int len2 = sizeof(arr2)/sizeof(int);
int len3 = sizeof(arr3)/sizeof(int);
printf("%d\n", len1);
printf("%d\n", len2);
printf("%d\n", len3);
for(int i=0; i<len2; i++){
printf("arr2[i] = %d\n", arr2[i]);
}
}
- 數(shù)組的遍歷
void print_arr(int arr[], int len){
for(int i=0; i<len; i++){
printf("arr[%d] = %d\n", i, arr[i]);
}
}
void print_arr2(int *p, int len){
for(int i=0; i<len; i++){
//通過索引取值
//printf("arr[%d] = %d\n", i, p[i]);
//通過地址值取值
printf("arr[%d] = %d\n", i, *(p+i));
}
}
void test4(){
int arr[] = {1, 6, 3, 4, 67};
int len = sizeof(arr) / sizeof(int);
print_arr(arr, len);
print_arr2(arr, len);
}
- 數(shù)組的排序
void test5(){
int arr[] = {1, 6, 3, 4, 67};
int len = sizeof(arr)/sizeof(int);
for(int i=0; i<len-1; i++){
for(int j=0; j<len-1-i; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int k=0; k<len; k++){
printf("arr[%d] = %d\n", k, arr[k]);
}
}
- 內(nèi)存模型 linux環(huán)境下
- Text段
- data段
stack
heap
static data//已經(jīng)初始化的常量或全局變量 - bss段 未初始化的常量和全局變量
- 內(nèi)存申請和釋放 動態(tài)數(shù)組
#include <stdio.h>
#include <stdlib.h>
void test6(){
int len = 3;
// void* p = malloc(len*sizeof(int));
//申請內(nèi)存
int *p1 =(int*) malloc(len*sizeof(int));
p1[0] = 0;
p1[1] = 1;
p1[2] = 2;
int i = 0;
for(; i<len; i++){
printf("p1[%d] = %d\n", i, p1[i]);
}
//釋放空間
free(p1);
}
int main(){
test6();
}
結(jié)構(gòu)體
- 結(jié)構(gòu)體定義方式
#include <stdio.h>
#include <stdlib.h>
//第一種定義方式 結(jié)構(gòu)體
struct Student{
char *name;
int age;
double score;
};
//第二種定義方式
struct Person{
char *name;
int age;
} person;
//第三種定義方式 匿名結(jié)構(gòu)體
struct {
char *name;
int age;
};
int main(){
//結(jié)構(gòu)體賦值
struct Student stu = {"張三", 23, 99.5};
printf("stu.name = %s, stu.age=%d, stu.double=%.2lf\n", stu.name, stu.age, stu.score);
person.name = "wwf";
person.age = 12;
printf("name = %s, age = %d\n", person.name, person.age);
}
- 結(jié)構(gòu)體指針
struct Student{
char *name;
int age;
double score;
};
int main(){
//結(jié)構(gòu)體賦值
struct Student stu = {"張三", 23, 99.5};
struct Student *p = &stu;
(*p).name = "龍飛";
(*p).age = 99;
printf("stu.name = %s, stu.age=%d, stu.score=%.2lf\n", stu.name, stu.age, stu.score);
//間接引用運算符
printf("stu.name = %s, stu.age = %d, stu.score = %.2lf\n", p->name, p->age, p->score);
//二級指針
struct Student **p2;
p2 = &p;
printf("stu.name = %s, stu.age = %d, stu.score = %.2lf\n", (**p2).name, (**p2).age, (**p2).score);
printf("stu.name = %s, stu.age = %d, stu.score = %.2lf\n", (*p2)->name, (*p2)->age, (*p2)->score);
}
- 結(jié)構(gòu)體大小
內(nèi)存開辟為2的整數(shù)倍, 各個數(shù)據(jù)類型的大小之和
struct Student{
char *name;//4byte
int age;//4byte
double score;//8byte
};
大小為16byte
- 結(jié)構(gòu)體中添加方法
int add(int a, int b){
return a+b;
}
// 結(jié)構(gòu)體
struct Student{
char *name;//4byte
int age;//4byte
double score;//8byte
int (*Add)(int, int);
};
int main(){
//結(jié)構(gòu)體賦值
struct Student stu = {"張三", 23, 99.5};
stu.Add = &add;
int result = stu.Add(1, 2);
printf("result = %d\n", result);
}
聯(lián)合體
#include <stdio.h>
#include <stdlib.h>
union Type{
char *a;
int b;
double c;
};
int main(){
union Type t;
t.a = "abc";
t.c = 124.1234;
return 0;
}
- 聯(lián)合體和結(jié)構(gòu)體區(qū)別
結(jié)構(gòu)體大小, 是所有數(shù)據(jù)大小之和,
聯(lián)合體共享內(nèi)存. 采用最大的那個數(shù)據(jù)類型大小, 聯(lián)合體賦值一次, 賦值多次沒有意
義, 因為后面的會覆蓋前面的數(shù)據(jù).
枚舉
enum DAY{
Mon, Tues, Web, Thur, Fri, Satu, Sun
};
int main(){
enum DAY today = Sun;
switch(today){
case Mon:
break;
case Tues:
break;
case Web:
break;
}
return 0;
}
typedef(給類型起別名)
typedef int size;
//給別名起別名
typedef size length;
typedef length width;
typedef length height;
struct Student{
char *name;
int age;
};
typedef struct Student *Stu;
int main(){
int a = 123;
size b = 123;
width c = 1;
height d = 2;
Stu s = {"玲玲", 21};
return 0;
}
宏定義(#define)
#define PI 3.1415926;
//方法模板
define AREA(r) PI * r * r;
int main (){
double result = AREA(2);
printf("result = %lf\n", result);
}
c語言語法
一. 字符串格式化輸出
- %d 整數(shù) int類型
- %s 字符串類型
- %f float類型
- %.3lf double類型, 保留3位小數(shù)
- %p 指針類型
- %% 打印一個百分號
- %c 字符類型
- \0 不可見字符, 字符串結(jié)尾, 存儲結(jié)束
- %hd short int 類型
- %u unsigned int
- %lu unsigned long
二. 隨機數(shù)
- arc4random_uniform(n)產(chǎn)生一個0到n-1的隨機數(shù)
- 10-20的隨機數(shù), 最大數(shù)-最小數(shù)+1 + 最小數(shù) 如下:
arc4random_uniform(20-10+1) + 10
三. goto語句
- 使用方法: 標簽名: 語句 在需要跳轉(zhuǎn)的地方, goto 標簽名, 容易造成死循環(huán), 如下
- 可以向前跳, 也可以向后跳.
- 只能在當前函數(shù)中使用
- 標簽名下面的第一行代碼, 不能定義變量
int main(int argc, const char * argv[])
{
loop:
// insert code here...
printf("Hello, World!33333\n");
float f = 1.234554654;
printf("f = %.2lf\n", f);
int r = random2(10);
if(r<6)
{
goto loop;
}
printf("r = %d\n", r);
return 0;
}
四. xcode調(diào)試
- 調(diào)試時, 高亮選中的代碼是一個函數(shù), 按下step over, 跳過函數(shù), 執(zhí)行下一步
- 如果, 想進入函數(shù), 按下step in
五. 原, 反, 補碼
- 正數(shù), 原反補碼, 一樣
- 負數(shù), 原反補碼, 不一樣
- short int num = 12; 在內(nèi)存中兩個字節(jié)
- int num = 1234; 四個字節(jié)
- long int num = 213435554; 8個字節(jié) 64位系統(tǒng), 4個字節(jié) 32位系統(tǒng)
六. 垃圾值的由來, 我們聲明一個局部變量, 在內(nèi)存回收的時候, 只是標記不在使用,
而不會清理內(nèi)存中的數(shù)據(jù), 再次分配給其他變量時, 數(shù)據(jù)會分配給新的變量.
七. 數(shù)組初始化方式
-
先聲明, 再賦值
int arr[3]; arr[0] = 1; arr[1] = 2; arr[2] = 3; -
聲明數(shù)組時, 初始化數(shù)組元素, 也可以省略數(shù)組長度
int arr[3] = {1, 2, 3}; int arr[] = {1,, 2, 3}; 賦值時, 指定數(shù)組元素個數(shù), 后面大括號中的元素可以不等于數(shù)組長度, 會自動截取, 或者補0
```
int arr[3] = {1, 2, 3, 4, 5};
int arr[3] = {1};
```
-
指定下標的初始化
int arr[3] = {[1]=2, [2]=3, [3]=4}; -
二維數(shù)組, 行數(shù)可以省略, 列數(shù)不能省略.
int arr[][4] = {1, 5, 3, 4, 6, 3, 8, 0, 8, 9, 12, 45, 23}; //行數(shù) int rows = sizeof(arr) / sizeof(arr[0]); //列數(shù) int cols = sizeof(arr[0]) / sizeof(arr[0][0]);
八. 字符串
字符串長度的計算 從左向右遍歷, 遇到\0結(jié)束.
-
常用函數(shù)
// 1, puts()函數(shù), 輸出字符串, 自動換行, 只能輸出字符串, 也不能使用占位符 char name[] = "jack"; puts(name); // 2, gets()函數(shù) 作用: 從控制臺接收一個字符串數(shù)據(jù), 與scanf的區(qū)別, // 可以接收空格, 和scanf()函數(shù)一樣, 不安全 char name[10]; printf("請輸入你的姓名: "); gets(name); puts(name); // 3, #include <string.h> // strlen(str) 字符串長度 char name[20] = "237748895985"; long len = strlen(name); printf("len = %lu\n", len); // 4, int strcmp(str1, str2) compare 比較字符串 // 等于0 相等 // 大于0 str1大 // 小于0 str2大 char name1[12] = "345454"; char name2[12] = "2345465768"; int num = strcmp(name1, name2); if(num==0){ } // 5, strcpy(str1, str2)函數(shù) copy, 將str1 拷貝到str2中\(zhòng)0也拷貝 // 6, strcat(str1, str2)函數(shù). concat: 鏈接 將str2連接到str1上 // 7, fputs(str, stdout); file 將字符數(shù)據(jù)輸出到指定的流中 標準輸入流和標準輸出流 stdin, stdout // 8, fopen(path, mode)函數(shù), 可以創(chuàng)建一個指向文件的指針. FILE * pFile = fopen("/Users/wwf/a.txt", "a"); char *name = "黑馬程序員"; fputs(name, pFile); fclose(pFile); // 9, fclose(file pointer)關(guān)流 // 10, fgets()函數(shù), 從控制臺接收用戶輸入字符串 scanf()缺點, 不安全, 輸入的空格會被認為結(jié)束 gets()缺點, 不安全 fgets(<#char *restrict#>, <#int#>, <#FILE *#>) 參數(shù)一: 將字符串存到那個數(shù)組中 參數(shù)二: 接收字符串的長度 參數(shù)三: 指定流 // 11, 從文件流中讀取內(nèi)容 FILE * pFile = fopen("/Users/wwf/a.txt", "r"); char name[50]; fgets(name, 50, pFile); fclose(pFile); printf("name = %s\n", name);
九. 指針: 變量的地址 指針在內(nèi)存中占據(jù)8個字節(jié)
-
指針變量 存儲指針的變量, 只能用來存儲地址
int *p1; int num = 10; p1 = # // p1的值 printf("p1 = %p\n", p1); // p1的地址 printf("p1 = %p\n", &p1); *p1 代表指針指向的變量
-
批量聲明指針
int *p1, *p2, *p3; // NULL 不指向任何地址, 完全等價于0 int *p1 = NULL; 野指針 聲明一個指針變量, 未初始化, 是一個垃圾值, 隨機的.
未初始化, 直接使用.-
多級指針
- 二級指針: 指針變量存儲的是, 一級指針的地址,
- 三級指針: 指針變量存儲的是, 二級指針的地址.
- 一級指針, 只能存儲普通變量的地址
- 二級指針, 只能存儲一級指針變量的地址
- 三級指針, 只能存儲二級指針變量的地址
- n級指針, 只能存儲n-1級指針變量的地址
int num = 12; int *p1 = # int **p2 = &p1; int ***p3 = &p2; -
指針的運算
- 指針可以和整數(shù)進行加減運算
- 指針+1 并不是+1, 而是增加一個單位變量所占用的字節(jié)數(shù)
- 指針之間只能做減法運算, 其他運算沒有意義
-
指針遍歷數(shù)組的元素
int arr[] = {3, 6, 3, 9, 23}; int *p = arr; int len = sizeof(arr)/sizeof(arr[0]); for(int i = 0; i < len; i++) { printf("arr[%d] = %d\n", i, *(p++)); } -
指針與指針之間的減法運算, 結(jié)果是一個long類型的數(shù)據(jù)
結(jié)果的意義代表兩個指針變量之間相差多少個單位變量
-
指針與指針之間,比較運算
內(nèi)存分配時, 先分配高字節(jié), 再分配低字節(jié).
十. 內(nèi)存中的五大區(qū)域
堆
棧
BSS段
未初始化的全局變量和靜態(tài)變量, 程序在剛運行的時候,未初始化.數(shù)據(jù)段/常量區(qū)
全局變量初始化為0后, 存到常量區(qū).
已經(jīng)初始化的全局變量, 靜態(tài)變量和常量等.代碼段
用來存儲程序的代碼/指令-
字符數(shù)組和字符指針的區(qū)別
// 都是以字符串數(shù)組存儲 //可以修改值 char arr[] = "jkklg"; //不可以修改值 char *arr1 = "dff"; // 字符串恒定性, 以字符指針形式存儲的字符串. -
從文件流中讀取字符串
FILE * pFile = fopen("/Users/wwf/a.txt", "r"); char name[50]; fgets(name, 50, pFile); fclose(pFile); printf("name = %s\n", name);
十一. const關(guān)鍵字 常量
-
const 修飾數(shù)組
int arr[4] = {1, 4, 6, 8}; //數(shù)組元素的值不能修改 -
const 修飾指針
// 無法通過p指針去修改指針指向的變量的值. 直接操作變量可以 int num = 14; const int *p = # // 可以把另外一個的變量的地址, 賦值給p int num2 = 15; p = &num2; // p的值不能改, 但是可以通過p修改指向的變量的值. int * const p = # *p = 16; // 都不能該 const int * const p = #
十二. 如何申請堆空間內(nèi)存
三個函數(shù): malloc(size_t) unsigned long類型, 申請, calloc(size, sizeof(int))申請, realloc()釋放; 申請多少個字節(jié)空間, 在stdlib.h頭文件中
堆中的空間是, 從低字節(jié)開始分配的,不一定連續(xù), 指的是多次molloc()分配內(nèi)存, 每一次分配的字節(jié)數(shù)是連續(xù)的; 棧中的空間, 從高字節(jié)開始分配, 連續(xù)的.
-
判斷是否申請成功,
int *p = malloc(4); if(p)//申請成功 等價于p!=NULL { } -
calloc函數(shù):
- 作用: 向堆空間申請指定字節(jié)數(shù)的空間
- 格式: 參數(shù)1: 多少個單位; 參數(shù)2: 每一個單位的字節(jié)數(shù)
- calloc(3, sizeof(int))
- 與malloc相比的優(yōu)勢, 申請內(nèi)存后, 系統(tǒng)會將字節(jié)中的數(shù)據(jù)清零.
-
realloc函數(shù)
擴容
注意: 指針 幾乎可以操作內(nèi)存上的每一個字節(jié). 但是我們還是建議, 不要亂來,
只操作我們申請的字節(jié)空間, 因為, 有可能出現(xiàn)一些問題.
如果長度不夠, 重新開辟一塊新的內(nèi)存將數(shù)據(jù)復(fù)制到其中, 將以前的內(nèi)存釋放.
-
長度夠, 還使用以前的內(nèi)存
int * arr = calloc(10, sizeof(int)); for(int i = 0; i < 10; i++) { arr[i] = (i+1)*10; } realloc(arr, 15);
指針作為函數(shù)的返回值, 不能使用局部變量的地址.
-
指向函數(shù)的指針聲明
- 指針函數(shù)的指針, 并不是任意的函數(shù)都可以指向
- 而是有限定的, 要求指向的函數(shù)的返回值類型和參數(shù)描述必須與指針的描述一樣.
- 聲明語法:
- 返回值類型 (*指針名) ([]參數(shù)列表)
void ( * pFun1) (); - int (*pFun2) (int num1, int num2);
- 返回值類型 (*指針名) ([]參數(shù)列表)
void test() { } int test2(int a, int b) { } int main(int argc, const char * argv[]) { void (*pFunc)() = test; pFunc(); (*pFunc)(); int (*pTest2)(int a, int b) = test2; pTest2(); }
十三. 結(jié)構(gòu)體
-
如何使用結(jié)構(gòu)體來創(chuàng)建新的數(shù)據(jù)類型呢?
語法格式:
struct 新類型名稱
{
// 在這里面寫上, 你創(chuàng)建的類型是由哪些變量聯(lián)合而成的.
數(shù)據(jù)類型1 小變量名稱1;
數(shù)據(jù)類型2 小變量名稱2;
數(shù)據(jù)類型3 小變量名稱3;
} -
別名:
typedef char* String; typedef struct { char *name; int age; char *sex; } Student; Student student;
十四. 宏定義
它是個預(yù)處理指令, 在編譯之前執(zhí)行, 在函數(shù)外, #define MAX = 10;
作用: 可以為一段c代碼定義一個標識, 如果你要使用這段c代碼, 那么你就使用這個標識.
語法: #define 宏名 宏值
原理: 在編譯的時候, 就會執(zhí)行源文件中的預(yù)處理指令.會將c代碼中, 使用宏名的地方替換為宏值.
將c代碼中的宏名替換為宏值的過程叫做 宏替換/宏代換
宏值可以是任意的東西, 定義時, 不會檢查語法, 宏替換時, 檢查語法
-
如果宏值是一個表達式, 那么宏值并不是表達式的結(jié)果, 而是它本身.
#define N = 10+10+20; int main(int argc, const char *argv[]) { int a = 2*N; printf("a = %d\n", a);//50 return 0; } 宏值不可更改
-
宏值可以是表達式,
#define C = a+a; int main(int argc, const char *argv[]) { int a = 10; int c = C; printf("c = %d\n", c); return 0; } 宏可以定義在函數(shù)外或者函數(shù)內(nèi)
宏從定義的地方一直到文件結(jié)束都可以用, 取消宏undef 宏名,
取消后, 后面就無法使用宏了-
使用宏的注意點:
#define MAX(a, b) a+b; // #define 空格 宏名 空格 宏值 -
static 和 extern
- 修飾成員變量, 在當前模塊中使用, 使用static, 跨模塊使用extern修飾
- 函數(shù)默認使用extern修飾,