C語言學習必須分清的幾個問題

來源:互聯網
上載者:User

1、指標數組和數組指標

指標數組本質為數組,只是數組的元素是指向某種類型資料的指標,其定義形式如下:

   類型名 *數組名[數組長度]。

數組指標本質上還為一個指標,只是這個指標指向的資料類型為數組,其定義形式如下:

   類型名 (*指標名)數組長度]

#include <stdio.h>void main(int argc,char argv[]){    int arr[4][4]= {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};    int (*p1)[4];  // 數組指標,指標指向int[4]的資料類型    int *p2[4];    // 指標數組,數組裡面的元素為指標    int i,j,k;    p1=arr;    for(i=0; i<4; i++)    {        for(j=0; j<4; j++)        {            printf("arr[%d][%d]=%d\t",i,j,*(*(p1+i)+j));// 通過數組指標輸出數組各元素        }        printf("\n");    }    for(k=0; k<4; k++) p2[k]=arr[k];// 此時的arr[k]為指向一維數組的地址,還可以使用*(arr+i)或arr+i來表示每行的起始地址    for(i=0; i<4; i++)    {        for(j=0; j<4; j++)        {            printf("arr[%d][%d]=%d\t",i,j,*((p2[i]+j)));// 使用指標數組輸出數組各元素        }        printf("\n");    }    return ;}

在Code:Blocks中運行,結果如所示。

2、指標函數和函數指標

指標函數是指帶指標的函數,本質上是一個函數,只是返回的是某種類型的指標,其定義的格式如下:

  類型標識符 *函數名(參數列表)

函數指標,從本質上來說是一個指標,只是它指向的不是一般的變數,而是一個函數。因為每個函數都有一個入口地址,函數指標指向的就是函數的入口地址。定義的基本格式如下:

  類型標識符 (指標變數名稱)(形參列表)

 

#include <stdio.h>// 函數指標的本質上是一個指標char* (*fun)(char *str,char *substr);void input(char *str,char *substr){    printf("請輸入字串:");    gets(str);    printf("請輸入要搜尋的字串:");    gets(substr);}int strlen(char *str)// 計算輸入str字串的長度{    int i=0;    while(str[i]!='\0')        i++;    return i;}char* search_str(char *str,char *search_str)// 指標函數{    int i,k,j;    k=strlen(str)-strlen(search_str);    if(k>0&&NULL!=str&&NULL!=search_str)    {        for(i=0; i<=k; i++)        {            for(j=i; str[j]==search_str[j-i]; j++)                if(search_str[j-i+1]=='\0')  return str+i+strlen(search_str);        }    }    return NULL;}void print(char* ret_str){    if(ret_str!=NULL) printf("搜尋之後的字串為:%s\n",ret_str);    else   printf("沒有找到字串\n");}void main(){    char str1[50],str2[50];    char search_str1[50],search_str2[50];    char * ret_str1,* ret_str2;    //------------------------------------------------    input(str1,search_str1);    ret_str1=search_str(str1,search_str1);//調用指標函數    printf("直接調用函數search_str()\n");    print(ret_str1);    //-------------------------------------------------    input(str2,search_str2);    fun=search_str;// 讓函數指標fun指向函數的入口地址,函數指標要與它所指向的函數具有相同的類型    ret_str2=fun(str2,search_str2);    printf("使用函數指標調用search_str()\n");    print(ret_str2);    return ;}

在Code:Blocks中運行,結果如所示。
 

 

3、指標與數組的關係

數組名在當作參數進行傳遞時,數組名為指向數組的指標。

#include <stdio.h>void copy_string(char from[],char to[]){    printf("careful,%d\n",'\0');    //C語言的while迴圈不同與Java的while迴圈,繼續迴圈的條件為非零,由於'\0'字元與整數的相通性,所以當為字串結束標誌'\0'時,while停止迴圈    while(*to++=*from++);// while迴圈在實現時,由於str字元數組的後面有結束符'\0',因此巧妙地將這一條件作為複製是否結束的標誌。    return ;}void main(){    char str[]="this is a string!";//完全超過了20個字元的長度??????    printf("%s\n",str);    char dec_str[20];    copy_string(str,dec_str);//在使用數組傳遞參數時,傳遞的是指向這個數組的指標變數    printf("%s\n",dec_str);    return ;}

在Code:Blocks中運行,結果如所示。

 

 

4、指標與字串的關係

在C語言中可以採用兩種方式來定義和訪問一個字串,一種是數組,另外一種是指標。但是通過數組定義的字串是可以進行修改的,而通過指標定義的字串在記憶體中只具有可讀屬性,不能在其後的代碼中做任何的修改,只可以引用。

 

5、指標在使用時必須分配記憶體單元

不能直接對未經初始化的指標進行賦值操作,所以賦值之前需要使用指標指向一個可用的地址空間,否則指標的指向是不確定的,在運行時會直接崩潰而退出。

#include <stdio.h>void copy_string(char from[],char to[]){    /*      1、在為to參數傳遞指標變數時,並沒有為dec_str分配儲存單元      2、在改變to指標變數指向後,to指向了可用的記憶體單元,而dec_str還是保持了以前的指向    */    to=(char*)malloc(sizeof(char)*20);// 是為指標指向的目標變數分配記憶體的大小,如果超過了這個大小??    char *start_to=to;    while(*to++=*from++);    printf("copy_string函數:%s\n\n",start_to);}void main(){    char str[]="this is a string!";//完全超過了20個字元的長度    printf("main函數:%s\n",str);    char *dec_str;    printf("copy_string函數調用前:%s\n",dec_str);    copy_string(str,dec_str);    printf("copy_string函數調用後:%s\n",dec_str);    return ;}

        在採用指標定義字串時沒有顯式地為指標分配內在,而編譯哭喊在編譯過程中會在記憶體中為字串分配一個記憶體地區,同時將分配後的首地址傳遞給指標變數,因此在通過指標定義字串時不必為其分配記憶體空間。

在Code:Blocks中運行,結果如所示。

#include "stdio.h"#include <sys/time.h>// const關鍵字,在為一個變數加上const修飾符後,通過需要對它進行初始化,在之後的程式中就不能再去改變它int main(int argc,char * argv[]){    char *str="Hello";    char s[8]="fdsa";    printf("strlen(str)=%d\n",strlen(str)); // 為5,表示字串的長度    printf("sizeof(str)=%d\n",sizeof(str)); // 為4,因為在32 位的電腦中,指標佔用4個位元組的長度    printf("sizeof(*str)=%d\n",sizeof(*str)); // 為1,由於str指標指向字串的首地址,而*str是指向第一個字元,當然為1    printf("字元數組的長度:%d\n",strlen(s));    //----------- 輸出字元數組中的值----------------    int i;    for(i=0; i<strlen(s); i++)// 不可以在for()中聲明int i=0,否則將出錯    {        printf("%d\n",s[i]);        printf("%c\n",s[i]);    }    //----------- 輸出字元數組中的值----------------    for(i=0; i<5; i++)// 不可以在for()中聲明int i=0,否則將出錯    {        printf("%c\n",*str);        str++;        printf("%d\n",strlen(str));// 注意,如果指標移動了,那麼指標所指向的字串長度也會相應縮小    }    return 0;}

 

6、指標的強制類型轉換

  

#include "stdio.h"int main(){    char *str="aaaabbbbccccdddd";    int *ptr;    ptr=(int *)str;    while(*ptr!='\0')    {        printf("%s\n",ptr);        ptr++;    }    printf("%s\n",str);//字元指標    return 0;}
 

7、位元組對齊的操作

#include <stdio.h>#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)4)->MEMBER) // 位元組對齊的操作typedef struct stu1{    int a;    int b;} stu1;void main(){    printf("offsetof(stu1,a):\%d\n",offsetof(stu1,a)-4);    printf("offsetof(stu1,b):\%d\n",offsetof(stu1,b)-4);    printf("%.2f",2.0);    return ;}

 

#include <stdio.h>typedef char * va_list;#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))// 對齊位元組的操作????????????????#define va_start(ap,v) (ap=(va_list)&v+sizeof(v)) //先擷取變數V的地址,然後轉換為char類型的指標,再加上變數V所佔用的記憶體大小,使指標ap指向下一個參數#define va_arg(ap,t) (*(t *)((ap+=sizeof(t))-sizeof(t)))// 先將指標ap強制類型轉換,,然後減去當前參數的地址#define va_end(ap) (ap=(va_list)0) // 清除ap指標void print(int n,...)// 變參函數的實現就是參數壓棧採用的4位元組對齊{    int arg,i;    va_list p;    va_start(p,n);// 進行了壓棧的操作    for(i=0; i<n; i++)// 迴圈取出壓棧的資料    {        arg=va_arg(p,int);// 當為arg=va_arg(p,char)時的情況為:只能取出一個A。因為壓棧是4位元組的操作,而取的時候為1個位元組,當然不行        printf("%c\t",arg);    }    printf("\n");    va_end(p);    return ;}int main(){    print(4,'A','B','C','D');    return 0;}

 

8、使用關鍵字進行類型的定義

#include <stdio.h>typedef int (*print)(int );// typedef是關鍵字,使用關鍵字進行類型的定義也屬於一個語句,後面需要加分號int fun1(int i){    return i;}void fun2(int n,print ptr){    int i;    for(i=0; i<n; i++)    {      printf("%d\t",ptr(i));    }}int main(){    int n=9;    fun2(n,fun1);    return 0;}

 

9、函數指標調用函數

 

#include <stdio.h>int max(int x,int y){    return x>y?x:y;}int min(int x,int y){    return x>y?y:x;}void main(){    int (*f)(int x,int y)=max;//定義了一個函數指標f,由於max或min代表函數的首地址,所以經過賦值後,指標f指向了函數代碼的首地址    printf("max(2,6)=%d\tf(5,4)=%d\n",max(2,6),f(5,4));// 指向函數的指標沒有自加或自減運算,這個需要注意    f=min;    printf("min(2,6)=%d\tf(5,4)=%d\n",min(2,6),f(5,4));}

 

10、變參列表 

#include "stdio.h"#include <stdarg.h>void print(int n,...){    int arg,i;    va_list p;// typedef char* va_list;    va_start(p,n);    for(i=0; i<n; i++)    {        arg=va_arg(p,int);        printf("%d\t",arg);    }    printf("\n");    va_end(p);    return ;}int main(){    print(3,35,25,64);    return 0;}

 

#include "stdio.h"void print(int n,...)// ...為函數的預留位置,是一個可變的參數{    int *p,i;    p=&n+1;    for(i=0; i<n; i++) printf("%d\t",p[i]);    printf("\n");    return;}int main(){    print(4,24,25,64,66);    char* str="Hello world!";    printf("%s\n",str);    return 0;}

 

7、其它需要注意的問題

1、 sizeof可以對一個運算式求值,但是不會對錶達式進行計算。當參數為函數時,得到的僅是函數體的傳回型別所佔用記憶體單元的大小,而函數體並不執行

2、沒有分配記憶體的指標變數指向的是不可使用的記憶體地區,所以如果要對指標變數進行初始化,必須先在記憶體單元中為其分配一塊可用的記憶體地區

3、對於定義的枚舉類型,不管它包含多少個枚舉常量,所佔用的記憶體大小都為4個位元組,與所使用的整型不同??

4、不能在定義數組後再對數組名進行一次性字串賦值,而指標可以採用這種方式進行初始化.如果結構體中存在數群組類型的成員,可以利用strcpy()函數對數組進行初始化,只能實現字元數組的初始化

5、typedef是關鍵字,使用關鍵字進行類型的定義也屬於一個語句,後面需要加分號

6、%.2lf表示以後兩個小數點的長整數

7、共用體成員共用同一片記憶體地區

#include "stdio.h"#include <sys/time.h>// const關鍵字,在為一個變數加上const修飾符後,通過需要對它進行初始化,在之後的程式中就不能再去改變它int main(int argc,char * argv[]){    char *str="Hello";    char s[8]="fdsa";    printf("strlen(str)=%d\n",strlen(str)); // 為5,表示字串的長度    printf("sizeof(str)=%d\n",sizeof(str)); // 為4,因為在32 位的電腦中,指標佔用4個位元組的長度    printf("sizeof(*str)=%d\n",sizeof(*str)); // 為1,由於str指標指向字串的首地址,而*str是指向第一個字元,當然為1    printf("字元數組的長度:%d\n",strlen(s));    //----------- 輸出字元數組中的值----------------    int i;    for(i=0; i<strlen(s); i++)// 不可以在for()中聲明int i=0,否則將出錯    {        printf("%d\n",s[i]);        printf("%c\n",s[i]);    }    //----------- 輸出字元數組中的值----------------    for(i=0; i<5; i++)// 不可以在for()中聲明int i=0,否則將出錯    {        printf("%c\n",*str);        str++;        printf("%d\n",strlen(str));// 注意,如果指標移動了,那麼指標所指向的字串長度也會相應縮小    }    return 0;}

 

#include "stdio.h"// 對判斷運算式的短路,也就是說有一部分會不執行// 無論對||還是&&都是一樣的// 對於float與double的比較,不能用!=或== 來比較,浮點運算存在精度問題,不能按照理論值來對其進行處理int fun(char *str){    printf("%s\n",str);    return 0;}void main(){    int a;    a=7;    if(a>9&&fun("a=7"));    a=10;    if(a>9&&fun("a=10"));    return ;}

 

#include "stdio.h"void main(){    double a=(double)6/5;// 先將6轉換為浮點類型,然後再將5隱式轉換為浮點類型後,為1.2    int b=(double)6/5;// 結果為1    printf("%f,%d",a,b);    return ;}

 

#include "stdio.h"void main(){    unsigned short i=0;    unsigned long n=0;    while(i<n-1)    {        printf("進入了while迴圈!");// ???????        break;    }    printf("i<n-1=%u\n",i<n-1);// n-1是無符號的長整型,發生了類型的隱式轉換    int y=0;    int k=-1;    printf("%d,%u\n",k,n-1);    return ;}

 

C語言分清的問題:

char str[100];

str[0]=='0'// 數組的第一個數為0字元

str[i]==0// 字串結束

str[i]=='  '// 空格
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.