1. 程式人生 > >c語言程式設計基礎

c語言程式設計基礎

1. c語言的特性

   A: c語言是一種底層語言

   B: c 語言是一種小型語言

   C: c 語言一種包容性語言,c語言假設使用者知道自己做什麼,

      所以她提供了更為廣闊的自由度。

   優點:

      高效

      可移植性,c語言編譯器規模小,容易編寫。

      功能強大

      靈活

      標準庫

      與UNIX 系統結合緊密

   缺點:

      出錯率高

      難理解

      難以修改

2.  gcc

gcc(  GNU Compiler Collection) 

基本用法:  gcc [options] [filenames]

-c  只編譯,生產.o 為字尾的目標檔案,通常用於編譯

     不包含主程式的子程式檔案。

-o  output_filename 確定輸出檔案的名稱為

-g  產生符號除錯工具gdb 所必要的符號資訊

-O  大寫哦對程式進行優化編譯

-O2  比-o 更好的優化編譯

-std    例如:  -std= c89 或者-std=c99

c程式(小全)巨集觀認識(程式碼角度,和記憶體角度)

一個較為完整的程式中,可以包含哪些部分?【描述記憶】

//系統標頭檔案
#include...

//巨集定義
#define....

//全域性變數
int data = 1;

//自定義函式的宣告


int main() //主函式
{
  //區域性變數 local
  int data=2;
  for()  //if  switch  while
  {
    //塊變數
    int data = 3;
  }
}

//自定義函式
。。。。。

C程式在記憶體中的分佈?

      程式段

        :程式碼段存放程式程式碼的一段區域,程式段是隻讀的。

      資料段

:存放已經初始化的全域性變數。

      bss段

:通常用來存放程式中未初始化的全域性變數和靜態變數的一塊記憶體區域

       堆

             堆:儲存程序中被動態分配的記憶體

             申請:malloc  remalloc(new) OC(alloc new init)

             釋放:free delete OC(release)

       棧

              棧:儲存了程式中臨時建立的區域性變數

變數,生命週期,作用域

1.1 區域性變數:【準確記憶】

我們把在函式體中定義的變數叫做這個函式的區域性變數。

Int main()

{

Int a,b,c,d........//區域性變數

}

Int test()

{

Int a; //區域性變數

}

 

區域性變數的特點;

1  生命週期:從定義這個區域性變數的地方開始,到函式的結束。

  1.   作用域(訪問範圍):在定義這個區域性變數的函式內(定義這個變數的以下語句);

1.2 靜態區域性變數

Static 修飾的區域性變數:

特點【描述記憶】

1 生命週期:整個程式

2 作用域:和普通變數一樣。

  1. 值:數值就是上一次函式呼叫結束之後的數值。

#include <stdio.h>

int test(){
	static int i=0;
	i++;
	printf("i = %d\n",i);
	return 0;
}
int main()
{
	int i=0; //這裡的i和test裡面的i不一樣
	for(;i<6;i++)
	{
		test();
	}
	return 0;
}

結果如下:

1.3 全域性變數

:定義在整個程式中的變數稱為全域性變數

  1. 生命週期:整個程式的生命週期之內
  2. 作用域(訪問範圍):整個程式的範圍內都可以訪問
  3.  值:沒有初始化的全域性變數的數值是0.

1.4  塊變數

:定義在語句塊裡面的變數叫做塊變數。

程式塊(語句塊):使用{}括起來的一組語句。

塊變數的特性:

  1. 生命週期:定義變數的地方開始,程式塊結束的地方消失
  2. 作用域(訪問範圍):程式塊內

for(......)

{

Int i = 0; //塊變數

}

 

If(......)

{

Int temp = i ; // 塊變數

}

變數優先順序:區域性優先原則

#include <stdio.h>

int data = 1;
int main()
{
	printf("data = %d\n",data);
	int data = 2; //區域性變數
	printf("data = %d\n",data);
	if(1)
	{
		int data = 3; //塊變數
		printf("data = %d\n",data);
	}
	return 0;
}

結果如下:

關鍵字修飾變數

Auto static  register

Static 修飾全域性變數

訪問範圍:只能在本檔案訪問。

即使在其他檔案中使用extern宣告也不能使用

Static 修飾函式

訪問範圍:

這個函式只能在本檔案中使用

什麼是自動變數?

普通區域性變數(static除外)都是auto ,auto 一般省略。

Auto  int i;

Register: 暫存器變數

:告訴編譯器這個變數會被頻繁的使用,請儲存到暫存器中。

使用限制【描述記憶】

  1. 必須能被cpu的暫存器接受(32位= 4個位元組)
  2. 不能對暫存器變數取地址  &

 

概念:

 型別:每個變數都必須宣告她的型別。C可分為基本資料型別和複合資料型別

宣告:任何變數在使用之前必須進行宣告。如:資料型別變數名稱

初始化:

  1.  自動變數未初始化的時候訪問,其數值是一個隨機數值。
#include  <stdio.h>
int main()
{
    int day;
    printf(“day = %d\n”,day);
    return 0;
}

識別符號:在編寫程式的時候,需要對變數,函式,巨集,以及其他實體進行命名,這些名稱成為:標示符。

標示符有五條命名規則:

  1. 以字母,下劃線開頭;
  2. 可以包含字母,下劃線,數字
  3. 大小寫敏感
  4. 不能和關鍵字衝突

關鍵字:

        特性:

       有特殊含義的一串字元

        全部小寫

        標準庫中函式名全部小寫

字串

字串的三種表示方式的區別?

  1. 字面值。存在於全域性區,不可改變。在記憶體中只有一個。
  2. Char  陣列存在於記憶體中函式棧,數值可以改變

    Char str[] = “abcde”;

     //賦值的時候

      Str = “abcde”;

   3. Char * 既可以指向字面值,也可以指向char 數組裡面的元素。

 

格式化輸入/輸出:

     printf( 格式字串,表示式1,表示式2,。。。。)  //可變長引數

    格式字串可分為兩個部分:普通字元和轉換說明

轉換說明包含以下幾部分:

完整格式:    %  - 0  m.n  l或者h   格式字元

  1.  %  佔位符  不能省略

  2.  -  左對齊,省略右對齊

  3.  0  代表空位填0  省略代表空位不填

  4.  m  域寬  n  精度

  5.   l  整數long, 浮點數double  ; h為  short;

 

  6.   i /d 輸出十進位制整數

                 O  無符號的八進位制整數

       X   十六進位制

       u  無符號的十進位制

       c   輸出一個字元

       s   輸出一個字串

f   輸出一個浮點數

e   以指數的形式輸出浮點數

g   在f和e格式之間選擇一個較短格式輸出

P  輸出一個地址

%m  輸出全域性error中錯誤

 2 %i%d 

  在printf裡面沒有區別

   在scanf  有區別

  %d  只匹配十進位制

  %i  八進位制  十進位制,十六進位制

3  如何輸出%

   %%

4. 4  scanf()   從鍵盤輸入

 絕大數情況下,scanf 只包含轉換說明。

scanf(格式字串,地址列表);

例如:scanf(“%f%f%f”, &s1, &s2, &s3);

整數在記憶體中的儲存? 【準確記憶】

    整型在記憶體中的儲存是按照補碼形式儲存的。整數的補碼與原始碼相同,

    負數的補碼就是其絕對值的二進位制形式按位取反,然後整個數值加  1.

進位制轉換 【理解描述】

sizeof 是c語言的一個關鍵字,不是函式。

sizeof(變數的名字)  或者sizeof (型別)

sizeof 返回一個物件或者型別所佔的記憶體位元組數

    sizeof 三種語法方式  b*****b 【準確記憶】

    1.  sizeof(型別)

    2.  sizeof(變數名)

    3.  sizeof(表示式)

int  i=5;

sizeof(i=10);

運算子:

算數運算子:+   -   *   /   %

  1.   /     0不能做除數,兩個整數相除,取結果的整數部分。
  2.   %   要求運算元都為整數,如果其中一個不是整數,編譯將無法通過。

賦值運算子

Int i,j;

複合賦值   +=   -=    *=   /=   %=

自增、自減

比較運算子:      ==

     推薦寫法:if(15 == data)

邏輯運算子的

  短路特性  b*****b【準確描述】

 &&   ||     ?:

例子:

#include <stdio.h>
int main()
{
	int i=0, j=0;
	if(++i || ++j);
	if(--i && ++j);
	printf("i = %d,j = %d\n",i,j);
	return 0;
}

 

位運算子

按位取反~3

按位與  &

    用途:  b***b 【記憶描述】

經常用來遮蔽某些二進位制位(置0)。也可以知道某個二進位制位是1還是0。

按位或  |

用途:  b***b【記憶描述】

經常用來將某些二進位制位(置1)。也可以知道某個二進位制位是1還是0。

按位異或  ^

      運算規則:b*****b 【準確記憶】

對應的二進位制位上的數字相同則為0,否則為1。

例子:判斷某個整數二進位制格式倒數第三位是0還是1?

If(data &4) ==4) 倒數第三位1

左移

規則:  b*****b 【準確記憶】

左移的時候右邊的空位補零

右移

規則:b*****b 【準確記憶】

右移的時候左邊補上符號位。

取地址運算

條件運算子

表示式1?表示式2:表示式3

 語句

if    else 語句

switch 語句

結構  

Switch(控制表示式)

{

Case 常量表達式1 :語句1;

Case 常量表達式2 : 語句2;break;

....

Default: .....

}

注意:

控制表示式:計算結果是整型

常量表達式:不能包含變數或者函式呼叫,最終結果必須是整數。

例如:n+10 不是常量表達式(除非n是表示常量的巨集),

每個分支中可以包含多條語句,可以不使用{}

迴圈語句:

for(表示式1;表示式2;表示式3)

{

語句;

}

 執行流程  表示式1 ==》 表示式2==〉迴圈語句==》表示式3==〉表示式2==》。。。

注意:可以這樣寫for(;;){....}

for(i=0;i<10;i++){...}

C99 第一個表示式可以為宣告例如:

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

for(i=0,j=0;i<10; printf(),i++,j++){....}

for迴圈可以巢狀

C語言中兩種常用的無限迴圈(死迴圈)方式? 

while(1)

for(;;)

do-while  迴圈

從鍵盤讀入:  scanf

 鍵盤--》 鍵盤緩衝區--〉 輸入緩衝區--》程式。

#include<stdio.h>
int main()
{
	int data_1 = 0, data_2 = 0;
	printf("請輸入兩個整數:");
	scanf("%d",&data_1);
	scanf("%d",&data_2);
	printf("您輸入的兩個整數是:%d %d\n",data_1,data_2);
	return 0;
}

 分析: scanf 失敗的原因: 型別不匹配

改成如下:

#include<stdio.h>
int main()
{
	int data_1 = 0, data_2 = 0;
	printf("請輸入兩個整數:");
	if(scanf("%d",&data_1) == 0)
	{
		scanf("%*[^\n]");
		scanf("%*c");
	}
	if(scanf("%d",&data_2) == 0)
	{
		scanf("%*[^\n]");  //讀走\n之前的所有字元
		scanf("%*c");//讀走字元包括之前匹配到的(*) c代表字元
	}
	printf("您輸入的兩個整數是:%d %d\n",data_1,data_2);
	return 0;
}

輸出緩衝區

程式--》輸出緩衝區--〉螢幕

程式的輸出可以到達螢幕的條件:  b*****b 【描述記憶】

    1,\n

 

  1.   程式結束
  2.   輸出緩衝區滿(4kb)
  3.   人工重新整理(fflush)

例子:

#include <stdio.h>

int main()

{

           printf("welcome!");

           while(1);

}

結果:沒有輸出

#include <stdio.h>

int main()

{

           printf("welcome!");

           fflush(stdout); //新增加的人工重新整理

           while(1);

}

 字串

讀取一個字串放到字元陣列中,然後列印

 

scanf(“%s”,&name);

scanf 遇到空白字元結束

 

gets(name)

從輸入裝置讀取一行字元回來,放到name中

危險:gets 不會考慮name的大小,可能導致name的溢位。

 

fgets(name,20,stdin);

fgets會在整個字串的後面新增\n

 

操作字串的庫函式

Strcpy

Strcat

Strncpy

Strncat

Strlen:
strcmp:

陣列和結構 (聚合型別)

陣列:

一維陣列初始化

Int a[5] = {1,2,3} ;  //【可描述】如果初始化裡面常量表達式個數小於陣列元素的個數,剩餘的元素初始化為零。

指定初始化

Int a[30] = { [19] = 54,  [9]=> 14, [29] = 45 };

#include <stdio.h>
int main()
{
	int a[10];
	printf("sizeof(a[0]) = %d\n",sizeof(a[0]));
	printf("sizeof(a) = %d\n",sizeof(a));
	char c[10];
	printf("sizeof(c[0]) = %d\n",sizeof(c[0]));
	printf("sizeof(c) = %d\n",sizeof(c));
	return 0;
}

結果如:

獲取陣列的個數?

巨集帶引數的巨集:
#define sz(a) sizeof(a)/sizeof(a[0])

c99中的變長陣列

Int n;

Scanf(“%d”, &n);

Int a[n]; //c99變長陣列

函式

函式的返回值

:函式的返回值必須和return 返回值的型別一致

  1.  如果函式沒有返回值指定為void
  2.  C語言的返回值型別可以省略預設為int

隱式宣告:如果函式在使用之前沒有進行宣告,編譯器會建立一個隱式宣告,返回值型別為int

值傳遞:c語言中實際引數和形式引數之間採用值傳遞的方式來傳遞資料。

#include <stdio.h>

void swap(int a,int b){
	int t=a;
	a=b;
	b=t;
	printf("swap:交換中:a = %d b=%d\n",a,b);
}
int main()
{
	int x=5,y=7;
	printf("main:交換之前:x= %d y= %d\n",x,y);
	swap(x,y);
	printf("main:交換之後:x= %d y= %d\n",x,y);
	return 0;
}

結果如下:

 

什麼時候使用const來修飾形參?【描述記憶】

如果形參傳遞的是地址,又不希望在被呼叫函式更改地址上的內容這個時候可以使用const修飾形參。

例如:

Int test(const int r[],int len)

{

r[len-1] = 100;

}

 指標作為返回值

注意:【描述記憶】

不要返回自動變數的地址。因為自動變數在函式結束之後所使用的記憶體會被釋放。

預處理

1.1 檔案包含

#include <xxx.h>

#include “xxx.h”

區別:

<>到系統指定的路徑尋找一般是:/usr/include

“” 優先從當前目錄開始,一般適用於自定義標頭檔案。

巨集

    1 簡單的巨集

     2.帶引數的巨集

//使用巨集判斷兩個整數中最大的那個

#define  MAX(x,y) (x)>(y)?(x):(y)

注意:                               todo;

引數不能是多次計算之後的數值

MAX(i++,j++)   //這是錯誤的

應該在每個引數的外面加上()

在整個表示式的外面加上()

例子:

#include <stdio.h>

#define MUL(x,y) x*y

int main()

{

           printf("結果:%d\n",MUL(3,5));

           printf("結果:%d\n",MUL(1+2,2+3));

           return 0;

}

 結果:

8不對呀!

#define MUL(x,y) (x)*(y)

改成上面這樣就對了

printf(“結果:%d\n”,30/MUL(3,5));

應該是2結果是50;

還要改,改成下面:

#define MUL(x,y)   ((x)*(y))

巨集運算子# 和##

  1. #

   #運算子有許多用途,這裡只來討論其中的一種。#運算子將巨集的一個引數轉換為字串字面量。#運算子所執行的操作可以理解為“字串化(stringization)”

   #define PRINT_INT(n) printf(#n " = %d\n",n)

  會變成:

  printf("i/j" " = %d\n",i/j);

  等價為printf("i/j = %d\n",i/j);

如果要被“字串化”的引數包含“或\字元,#運算子會將"轉換為\",\轉換為\\。考慮下面的巨集:

#define STRINGIZE(x) #x

前處理器會將STRINGIZE("foo")替換為”\“foo\""。

  1. ##   將兩個識別符號貼上在一起形成一個識別符號

#define  MAX(type) type max_##type()

MAX(float)  對應如下:float max_float()

#define MK_ID(n) i##n

int MK_ID(1),MK_ID(2),MK_ID(3);

預處理後這一宣告變為:int i1,i2,i3;

注意:##的巨集通常不能巢狀呼叫

#define cat(x, y) x ## y那麼,巨集呼叫cat(var, 123)將生成var123。但是,巨集呼叫cat(cat(1,2),3)沒有定義

預定義的巨集

1 __LINE__

2 __FILE__

3 __DATE__

4 __TIME__

5  __STDC__ //判斷編譯器是否符合c 標準  返回0或者1

1.5 條件編譯:

條件編譯就是根據前處理器的執行結果來包含或者排除某一段程式。

#if #endif

defined : 判斷一個巨集(有沒有定義過這個巨集)

#define Debug

#ifdefined Debug

....

#endif

3 #ifdef  // 等價於  #if  defined

4 #else

#if ...

程式碼

#elif ...

程式碼

#else

程式碼

#endif

為什麼要用條件編譯?

【描述記憶】

1,編寫多種硬體環境或者多作業系統上執行的可移植程式。

2,編寫用於不同編譯器的程式。

               #if  __STDC__

                函式

                  #else

                  函式

                  #endif

  3. 產品的除錯與釋出

  4.  為巨集提供定義

多原始檔的程式編譯方法?

1 首先對每一個原始檔只編譯不連線

gcc -c .....

生成xx.o 檔案

2 連線成為一個可執行程式

gcc *.o

自定義的標頭檔案

  1. 共享巨集定義
  2. 全域性變數的宣告
  3.  型別定義共享

extern int r //告訴編譯器,該變數已經在其他檔案

例子:

 

解決方法:把test.c中的新增一行  extern int speed;

 重複包含一個頭檔案,可能會導致編譯錯誤。怎麼做呢?

【描述記憶】

正確的自定義標頭檔案的編寫。

例如:

Test.h

#ifndef TEST_H

#define TEST_H

 

#include <stdio.h>

#define DISTANCE 1270

#define OIL 13

 

#endif

 

makefile

 

 描述:makefile 由很多規則組成,一條規則可以分為:

目標檔案:依賴檔案

命令(生成目標檔案所執行的指令,可以是多條)

結構

定義:

typedef struct

{

成員列表

} 別名;

使用結構指標作為函式的引數和返回值的時候,可以使程式的效率提高!

結構體位段

位段/位域

struct s{

Int i:3;  //指定i在記憶體中佔用3個二進位制位。

Int b:1;

.....

}

 

例子:

#include <stdio.h>

//結構體型別的宣告
struct test
{
	char c1:1;
	char c2:2;
	char c3:3;
};

int main()
{
	printf("sizeof(struct test) = %d\n",sizeof(struct test));
	return 0;
}

結果如下:

 

聯合

1, 可以有多個不同型別的成員的組成

2,通過成員的名字訪問成員

3,所有成員公用起始地址相同的一段記憶體

#include <stdio.h>

union
{
	int i;
	double d;
} test;

int main()
{
	printf("sizeof(union test) = %d\n",sizeof(test));
	return 0;
}

結果:

大端:低地址儲存高位資料

小端:低地址儲存低位資料

大小端更詳細說明: http://blog.csdn.net/u013862108/article/details/78961961

列舉型別

規則:enum 列舉名{列舉常量}; //列舉常量之間使用逗號分隔

#include <stdio.h>

int main()
{
	enum color {RED,BLUE,GREEN};
	//本質上列舉常量就是整數
	
	enum color c;
	c = 0;  //僅限c語言中
	c = BLUE;
	printf("RED=%d BLUE=%d GREEN=%d\n",RED,BLUE,GREEN);
	return 0;
}

結果如下:

 記憶體分配

自動變數:記憶體都是作業系統維護的。

堆:自己申請自己釋放

棧:自動分配自動釋放

動態分配記憶體的函式malloc calloc realloc

Malloc -- 分配記憶體塊,不會對分配的記憶體進行初始化

Calloc -- 分配記憶體塊,對記憶體進行清零

Realloc -- 調整先前已經分配的記憶體塊的大小

malloc :

Void * malloc(size_t size)

malloc 分配size位元組的記憶體,返回指向這塊記憶體的指標

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int n = 0, i=0;
	printf("請輸入陣列的大小:");
	scanf("%d",&n);
	int *q = (int *)malloc(n*sizeof(int));
	if(q == NULL)
	{
		//分配失敗
		printf("error:分配失敗\n");
		return 0;
	}
	for(;i<n;i++)
	{
		q[i] = i+1;
	}
	for(i=0; i<n; i++)
	{
		printf("%d ",q[i]);
	}
	printf("\n");
	free(q); //釋放動態記憶體
	q = NULL; //置為空指標
	return 0;
}

結果:

字串的malloc分配

Char *q = (char *)malloc(n+1);

結構體的malloc分配

Struct employee *e = (struct employee *)malloc(sizeof(struct employee));

Void * calloc(size_t nmemb, size_t size);

Calloc 為nmemb個元素分配記憶體,每一個元素都是size 個位元組大小,自動清零

 

realloc

:可以根據需求動態的調整已經分配好的記憶體。

引數幾種情況:

  1. 記憶體擴張,realloc 不會初始化擴張的記憶體
  2. 失敗了,返回空指標,不會影響原來塊中的資料
  3. 第一個引數NULL, 相當於malloc
  4. 第二個引數0,釋放原來的記憶體塊

檔案

檔案指標:就是指向FILE結構體的指標。

FILE * fp; //fp就是一個檔案指標

檔案的操作

 fopen:  開啟一個檔案

fclose: 關閉一個檔案

檔案的讀寫

Int fputs() 將一個字元寫到檔案中

fgetc(); //從檔案中讀一個字元出來 ?


#include <stdio.h>
int main(int argc ,const char *argv[])
{
	FILE *fp = NULL;
	if(argc<2 || argc>2)
	{
		printf("命令的格式不對\n");
		printf("Useage:command filename\n");
		return 0;
	}
	if((fp = fopen(argv[1],"r")) == NULL)
	{
		printf("檔案開啟失敗:%m\n");
		return 0;
	}
	char c;
	while(1)
	{
		c = fgetc(fp);
		if(c==EOF)
			break;
		else
			printf("%c",c);
	}
	fclose(fp);
	return 0;
}

例子: fgetc,  fputs 檔案的複製功能?

/*檔案複製*/
#include <stdio.h>
int main(int argc ,const char *argv[])
{
	if(argc !=3)
	{
		printf("格式不對\n");
		return 0;
	}
	FILE *fp1 = NULL;
	FILE *fp2 = NULL;
	if((fp1 = fopen(argv[1],"r")) == NULL)
	{
		printf("開啟%s失敗\n",argv[1]);
		return 0;
	}

	printf("成功開啟%s檔案\n",argv[1]);
	if((fp2 = fopen(argv[2],"w")) == NULL)
	{
		printf("開啟%s失敗\n",argv[2]);
		fclose(fp1);
		return 0;
	}
	printf("成功開啟%s檔案\n",argv[2]);
	char c;
	while(1)
	{
		c = fgetc(fp1);
		if(c== EOF)break;
		else
			fputc( c,fp2);
	}
	fclose(fp1);
	fclose(fp2);
	return 0;
}

C語言提供的讀寫資料塊的函式

Size_t fread(buffer,size,count,fp)

Size_t fwrite(buffer,size,count,fp)

 使用fwrite 寫兩個整數到檔案中?

/*檔案複製*/
#include <stdio.h>
int main(int argc ,const char *argv[])
{
	int i=15, j=63;
	FILE * fp = NULL;
	if((fp = fopen("c.txt","w")) == NULL)
	{
		printf("fail to open the file:%m\n");
		return 0;
	}	
	printf("success to open the file\n");
	fwrite(&i,sizeof(i),1,fp);
	fwrite(&j,sizeof(i),1,fp);
	fclose(fp);
	return 0;
}

檢視寫入的結果:

 

 使用fread 讀出來?

/*檔案複製*/
#include <stdio.h>
int main(int argc ,const char *argv[])
{
	int i = 0,j = 0;
	FILE *fp = NULL;
	if((fp = fopen("c.txt","r")) == NULL)
	{
		printf("fail to open the file:%m\n");
		return 0;
	}
	printf("success to open the file\n");
	if(fread(&i,sizeof(i),1,fp)!=1)
	{
		printf("讀取失敗\n");
	}
	if(fread(&j,sizeof(j),1,fp)!=1)
	{
		printf("讀取失敗\n");
	}
	printf("i = %d j=%d\n",i,j);
	fclose(fp);
	return 0;
}

執行結果如下:

 檔案的定位 rewind

Rewind 函式使位置指標回到檔案的開頭。

 

Fseek 函式

Int fseek (FILE *stream,long offset, int whence)

        Stream: 檔案指標

        Offset: 位移量

        Whence: 起始點

        檔案開頭0 SEEK_SET

        當前位置1 SEEK_CUR

        檔案末尾2 SEEK_END

儲存三個員工的資訊(struct) 到檔案中,然後顯示出來?

#include <stdio.h>

typedef struct
{
	int ID;
	char name[30];
	float salary;
} employee;
int main(int argc ,const char *argv[])
{
	employee e[3] = {{1, "趙志",500},{2,"月月",500.5},{3,"阿龍",600}};
	FILE *fp = NULL;
	if((fp = fopen("d.txt","w+")) ==NULL)
	{
		printf("fail to open the file:%m\n");
		return 0;
	}
	printf("success to open the file\n");
	int count = 0;
	if((count = fwrite(e,sizeof(employee),3,fp))<3)
	{
		printf("write error:%m\n");
	}
	fseek(fp,-3*sizeof(employee),SEEK_CUR); //rewind
	employee temp;
	int i = 0;
	for(;i<3;i++){
		fread(&temp,sizeof(employee),1,fp);
		printf("工號:%d 姓名:%s 薪資:%g\n",temp.ID,temp.name,temp.salar
y);
	}
	fclose(fp);
	return 0;
}

執行結果如下:

檔案讀寫的其他函式

Fgets fputs

從指定檔案中讀取或者寫入一個字串

char str[500]  //fgets(str,n,fp) n 為指定讀取字元的個數,但是fp只能讀出n-1 最後加’\0’

fputs

fprintf 和fscanf  格式化讀寫注意:效率低,大量資料用fread  fwrite

標準庫 

stdlib.h

無法劃歸到其他標頭檔案中的

字串,數字,產生隨機數,記憶體管理  系統通訊搜尋排序等

c語言的宣告

宣告int *p[3]; 使用如:*p[i] , “宣告的形式和使用的形式相似” 這種用法可能是C 語言獨創的,其他語言沒有采取這種方法。貝爾實驗室學者們也承認批評有理,但他們堅決死扛原來的決定,至今依然。

宣告是如何構成的?

  宣告器declaratory) : 就是標示符以及與它組合在一起的指標,函式括號,陣列下表等。

數量

C語言中名字

出現的形式

零個或多個

指標

下列形式之一:

*const volatile

*volatile

*

* const

*volatile const

有且只有一個

直接宣告器

標示符

標示符[下標]

標示符(引數)

(宣告器)

零個或一個

初始化內容

= 初始值

 

不合規則的宣告,或宣告中存在的限制條件?

        1. 函式的返回值不能是一個函式
        2. 函式的返回值不能是一個數組
        3. 數組裡邊不能有函式  。如foo[]()  是非法的

結構的宣告

例如:

struct  { 內容。。。} plum , pomegranate, pear; 

struct fruit_tag { 內容。。。} plum ,pomegranate, pear;

 

更常用的,或更建議的宣告方式是:

struct veg { int weight, price_per_lb; };    //型別宣告,可與php中類對比類的宣告,例項化

struct veg onion,radish, turnip;          //變數的宣告

聯合的宣告?

聯合一般是作為大型結構的一部分存在的。聯合一般被用來節省空間

實際工作中,結構的使用的次數將遠遠大於聯合。

列舉的宣告?

   一般來說,用列舉的地方都可以用#define 來解決。

           enum  可選標籤{ 內容。。。}可選變數定義; 

           列舉和#define 對比:列舉具有一個有點:#define 定義的名字一般在編譯時被丟棄,列舉名字則通常一直在偵錯程式中可見,可以在除錯程式碼時使用他們。