標準C基礎知識五

honghu79 12年前發布 | 2K 次閱讀 建站 Tiny Core Linux google應用商城


 函數的形參和局部變量在調用時與上次調用時的值無關;形參每次都會被覆蓋,局部變量每次調用完都會被釋放。
 靜態局部變量(在多次調用時并不釋放以前的分配空間)與上次調用時的值有關。
 
 
 
 
 
 值傳遞
 
 vi byvalue.c
 #include <stdio.h>
 
 void swap(int a,int b)//交換兩個變量的值;也可以使用異或來進行交換,但要考慮溢出
 {
  printf("in:m=%d,n=%d\n",m,n);
  printf("a:%p,b:%p\n",&a,&b);
  int t=a;
  a=b;
  b=t;
  printf("out:m=%d,n=%d\n",m,n);
 }
 
 int main()
 { 
 
  int  m=10,n=20;
  printf("m:%p,n:%p\n",&m,&n);
  swap(m,n);
  printf("m=%d,n=%d\n",m,n);
  return 0;
  
 }
 //程序從main主入口運行后,m=19,n=20;
 //調用swap(m,n)函數;把m=19值復制給a;n=20的值復制給b;
 //通過swap后,a和b的值互換,a=20;b=19;但m,n的值不變
 //也可以通過獲取變量的地址來進行比較看是否同一個變量或對象;&a
 
 編譯gcc byvalue.c
 運行a.out
 結果:
 in:a=10,b=20
 out:a=20,b=10
 m=10,n=20
 
 
結構作為函數的形參
 
 #include <stdio.h>
 typedef struct date{
  int year;
  int month;
  int day;
 }date;
 
 date input ()//void input (date d)--->理解形參實參在調用的時候是否同一
 //要確認形參是需要的
 //在C語言中,形參為空時,表示形參個數或類型不定。
 //如何表示不傳參數呢?(void)
 {
  date d;
  printf("d of function input:%p\n",&d);
  printf("請輸入年月日");
  scanf("%d%d%d",&d.year,&d.month,&d.day);
  return d;
  
 }
 void print(date d)
 {
  printf("%d-%d-%d\n",d.year,d.month,d.day);
 }
 int date2int(date d)//把日期轉化稱整數如:2012-04-27 ---> 20120427
 { 
  return (d.year*10000+d.month*100+d.day);
 
 }
 date int2date(int n)//把整數轉換成日期格式如:20120427---->2012-04-27
 {
  date d;
  d.day=n%100;
  d.year=n/10000;
  d.month=n/100%100;
  return d;
 }

 
 int main()
 {
  date d;
  printf("d of function main:%p\n",&d);
  //input(d);//input(date d);這種寫法是錯誤的。
  d=input();
  printf(d);
  int n=date2int(d);
  printf("%d\n",n);
  printf(int2date(n));
  return 0;
  
 }
 
 
 //形參和實參,可能名字相同,數值相同,但不在同一個地方,是兩個不同的變量;
 
 日期格式轉換,比如把日期轉換成整數,把整數轉換成日期格式;2012-04-27《----》20120427
 
 
數組作為值來傳遞
 
 #include <stdio.h>
 
 
 void print(int a[],int n)
 {
  int i;
  for (i=0;i<n;i++){
   printf("%d ",a[i]);
  }
  printf("\n");
  
 }
 void add(int x[],int n)//元素數值是原來的2倍;1、可以2;也可以左移
 {
  int i;
  for (i=0;i<n;i++){
  
   x[i]<<=1;//左移+賦值
  }
 
 }
 void reverse(int x[],int n)//元素倒序,交換位置
 {
  int i;
  for (i=0;i<n/2;i++)
  {
   int t=x[i];
   x[i]=x[n-1-i];
   x[n-1-i]=t;
  
  }
 
 }
 
 int main()
 {
  int a[5]={11,22,33,44,55};
  int b[6]={1,2,3,4,5,6};
  print(a,5);
  print(b,6);
  add(a,5);
  print(a,5);
  reverse(a,5);
  print(a,5);
  return 0;
 }
 //向函數傳遞數組時,我們一般會傳遞兩個參數:1\首地址;2\元素個數
 
 形參數組和實參數組實際上是同一組數組,在內存中同一個地方。---》這樣的話,也就沒必要再return返回數組了。
 
 
如何才能傳入更多的參數,傳多少參數都可以;比如printf和scanf

  #include <stdio.h>
  
  int main()
  {
   printf("hello\n");
   printf("%d,%c\n",123,65);
   printf("%f\n",4.5);
   printf("%f,%s\n",123,65);//報錯
   return 0;
  }
  
  man -s3 printf
  
  (,...) //不定長
  
  va_start  va_arg va_end  va_list函數用來處理不定長參數表;靠占位符來識別有幾個數據
  
  如max(5,18,55,93,25,67)   max("%d%d%d%d%d",18,55,93,25,67)
  max(2,83,69)    max("%d%d",83,69)
  
  函數可以定義為:int max(int n,...)
  
如何來用呢?
  vi variable_arguments.c
  //求任一個整數的最大值
  #include <stdio.h>
  #include <stdarg.h>
  int max(int cnt,...)
  {
   va_list v;//va_list類型,v保存可變長參數表;v實際上是一個地址類型
   va_start(v,cnt);//不定長參數表之前至少有一個固定形參;用v保存參數cnt之后的那些參數
   int i;
   int maxvalue=va_arg(v,int);//從參數表中取出一個int類型的參數
   for (i=1;i<cnt;i++){
    int data=va_arg(v,int);//從參數表中取出一個int類型的參數
    if (data>maxvalue){
     maxvalue=data;
    }
   }
   va_end(v);//釋放可變長參數表v
   return maxvalue;
  }
  void printstring(int cnt,...)
  {
   va_list v;
   va_start(v,cnt);
   int i;
   for (i=0;i<cnt;i++){
    puts(va_arg(v,char*));
   }
   va_end(v);
  }
  int main()
  {
   printf("%d\n",max(2,88,69));
   printf("%d\n",max(5,91,25,86,97,89));
   printf("%d\n",max(4,93,65,76,87));
   printstring(3,"hello","my","dear");
   return 0;
   
  }
  
  不定長參數類型會提升:
  char,short===》int
  float===》double
  
  
  #include <stdio.h>
  
  int f(int x)
  {
   printf("call f(%d),&x=%p\n",x,&x);
   if(x<=0)
    return 5;
   else
    return 2*f(x+1)+3;
  }
  
  int main()
  {
   printf("%d\n",f(3));
   return 0;
  }
  
  //該程序在運行的時候會出現段錯誤;怎么解決呢?必須有終止條件
 
  //if控制的內容如果以return結束,else可以省略
  
 
 ABC3個位置上,每個位置上放了N個盤子,將盤子從A放到B位置,只能是從最上面開始移動,一次一個
 
 vi hano.c
 
 #include <stdio.h>
 
 void hano(char from,int  n,char to ,char spare)
 {
  if(n>0)
  {
   hano(from,n-1,spare,to);//把上面n-1個盤子移到空位
   printf("move %d %c==>%c\n",n,from,to);//移動到第n個
   hano(spare,n-1,to,from);//把空位上n-1個盤子移動到目的地
   
  }
 }
 
 int main()
 {
  hano('a',5,'b','c');
  return 0;
 }
 用遞歸:
 1、找遞推關系
 2、找終止條件
 遞歸必須有終點,要不一會兒就會把棧占用完

 
 每個函數在執行完畢后都會回到開始執行的地方;即使沒有返回值(傳遞值)也會用到棧。每次調函數的時候,程序都會返回地址存到棧里面
 每次調用,都會新分配內存空間,都會用到棧;也就利于返回和復原;
 

 vi decbit.c
 #include <stdio.h>
 void decbit(int n)
 {
  if (n>9){
   decbit(n/10);
  }
  printf(" %d",n%10);
 }
 int main()
 { 
  decbit(53926);
  printf("\n");
  return 0;
 }
 
 
 1 1 2 3 5 8 13 21 34 55 89 ....   fibonacci;數列
 
 函數盡量先聲明后使用
 
 特殊函數  宏函數  macro
 
 
 vi macro.c
 #include <stdio.h>
 #define PI 3.14159 //常量
 #define P print(
 #define H "hello\n");
 #define I int n;printf("請輸入一個整數:");scanf("%d,&n");\
  printf("您輸入的是%d的一半\n",n+n);
 //  \為續行符
 #define MA int main(){
 #define END return 0;}
 #define W "wahaha"
 #ifndef H
  #define H "你好!\n");
 #else
  #define _H  H
  #undef  H  //取消
  #define H "****\n");
 #endif
 
 int main()
 {
  
  P H //編譯的時候做個替換
  I
  return 0;
  
 }

 頭文件
 vi head.h
 //定義一個結構類型
 struct s{};
 typdef struct s s;
 s input();
 void print(s,a);
 
 vi head.c
 #include <stdio.h>
 //#include "head.h"
 //#include "func.h"  //理解:head.h和func.h中重復定義了s
 //int x=2;
 //int x=3; //編譯也會報錯

 #ifndef VX
 #define VX 1   //習慣上定義為1
 int x=2;
 #endif
 #ifndex VX
 #define VX 1   //習慣上定義為1
 int x=3;
 #endif
 int main()
 {
  s a;
  return 0;
 }
 
 vi func.h
 s input();
 void print(s,a);
 
 
 
 一般頭文件都是采用以下結構:
 #ifndef VX   //VX命名一般按照頭文件名來命名如head.h在這里命名為HEAD_H
 #define VX 1
 ......
 #endif
 
 vi heard.c
 #ifndef HEAD_H
 #define HEAD_H 1
 struct s;
 typedef struct s s;
 #endif
 
 C語言本身有幾個已經預定義好的宏
 vi predef.c
 #include <stdio.h>
 int main()
 {
  __FILE__  //字符串
  __LINE__  //整數
  __DATE__  //字符串
  __TIME__  //字符串
   //——STDC——  //字符串
  return 0;
 }
 
 帶參數的宏;宏函數;處理的時候還是原樣替換
 
 vi mfunc.c
 
 #include <stdio.h>
 #define SWAP(T,x,y){T t=x;x=y;y=t;} //交換2個數值
 #define MAX(x,y){x<y?y:x} //x,y誰大
 #define PI 3.14159
 #define AREA(r) PI*(r)*(r)  //帶參數的宏,后面一定要有();可以通過編譯時加-E來看效果
 #define STR(X) puts(#x)  //puts("hello")
 void welcomestudent(){printf("歡迎各位同學");}
 void welcometeacher(){printf("歡迎各位老師");}
 #define welcome(who) welcome##who()
 int main()
 {
  int a=10,b=20;
  double c=12.3,d=45.6;
  SWAP(int,a,b)
  SWAP(double,c,d)
  printf("a=%d,b=%d\n",a,b);
  printf("c=%g,d=%g\n",c,d);
  printf("%d\n",MAX(a,b));
  printf("%g\n",AREA(10));
  STR(hello);
  
  return 0;
 }
 
 //調用宏函數的時候,盡量不要用++,--,賦值的式子
 
 //宏的優勢:不存在傳遞參數等;直接把需要的數據放在相應的位置,速度快。
 
 ##把參數和其他的東西拼接在一起
 
 #include <stdio.h>

 #define ISLEAP(y)((y)%4==0&&(y)%100!=0||(y)%400==0)
 #define ISSMALL(m)((m)==4||(m)==6||(m)==9(m)==11)
 #define NORMAL(y,m)(ISSMALL(m)?30:31)
 #define DAYS(y,m)((m)==2?28+ISLEAP(y):NORMAL(m))
 #define IN(x,from,to)((x)>=(from)&&(x)<=(to))
 #define ISVALID(y,m,d)((y)>1600&&IN(m,1,12)&&IN(d,1,DAYS(y,m)))
 
 int main()
 {
  printf("%d,%d,%d\n",DAYS(2012,2),DAYS(2010,8),DAYS(2012,4));
  return 0;
 }
 C語言的話,宏使用比較多,而在C++相對來說比較少
 
 指針
 char*地址,每個變量在內存中總有個地址;所謂的地址就是開始地址
 1個指針保存的是地址=====》類似于硬盤中的lba地址(定位扇區用)
 地址不是孤立的,總是帶著類型;即通過尋址后,取那種類型的變量
 
 
 vi pointer.c
 #include <stdio.h>
 
 int main()
 {
  char x[8]={'a','b','c','d','e','f','g','h'};//不是字符串,通過puts輸出時可能會有亂碼
  //char x[9]={'a','b','c','d','e','f','g','h'};//一定不會有亂碼;不夠的時候,會用0來補;而0使用'\0'來表示
  puts(x);
  
  char* p1;
  p1=&x[0];//表示取x[0]的地址;char*
  
  char* p2=&x[2];//初始化;//char*,表示的char*類型
  printf("%c\n",*p1);
  *p1='A';
  *p2='C';
  puts(x);
  int * p3=&x[3];//char * 在編譯時會報不兼容的指針類型初始化警告
  printf("%X\n",*p3);
  return 0;
  
 }
 
 //在定義變量的時候,*不是運算符,不表示運算
 

 本文由用戶 honghu79 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!