程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言函數返回值解析

C語言函數返回值解析

編輯:關於C語言

程序一:

int main()
{
    int *p;
    int i;
    int*fun(void);
    p=fun();
    for(i=0;i<3;i++)
    {
        printf("%d\n",*p);
        p++;    
    }
    return 0;
};
int* fun(void)
{
    static int str[]={1,2,3,4,5};
     int*q=str;
    return q;
}

//不能正確返回

雖然str是在動態變量區,而該動態變量是局部的,函數結束時不保留的。

程序二:

int main()
{
    char *p;
    char*fun(void);
    p=fun();
    printf("%s\n",p);
    return 0;
};
char * fun(void)
{
    char *str="hello";
    return str;
}

//可以正確返回

但是,字符串"hello"不是變量,而是一個常量,編譯程序在處理這種常量時,通常把它放在了常量區中。而常量區則是始終存在的。

後一個例子中函數fun的返回值就是一個指向這種常量區的指針。

函數返回指針,要使主程序可以使用這個指針來訪問有意義的數據,關鍵就是要保證在使用這個指針值的時候,該指針所指向的地方的數據仍然有意義。

還有,如果指針是指向函數的指針,那麼這個指針就是指向程序代碼區的。這也是一種應用的情況。

另外,如果明白了它的原理,程序員還可以發明出一些其他靈活的使用方法,當然,那都屬於“怪”方法,一般不提倡的。

程序三:

int main()
{
    int a,b;
    int max;
    int fun (int a,int b);
    scanf("%d%d",&a,&b);
    max=fun (a,b);
    printf("\n%d\n",max);
    return 0;
};
//http://www.bianceng.cn int fun(int a,int b)
{
    int max;
    if(a>b)
        max=a;
    else
        max=b;
    return max;
}
//可以正確返回

程序三:

這個例子中,返回的不是變量max的地址,返回的是它的值。

return後面的東西,看做一個表達式,返回的是這個表達式的值。

例如,入口如果a是3,b是5,則此時(執行return語句時)max裡面存的是5。而return語句的功能就是把max裡面的5取出來,放到“返回值寄存器”中。

主程序是從“返回值寄存器”得到這個5的(此時max變量已經不存在了)。

你前面的第二個例子中,同樣,指針變量str在函數結束後已經不存在了。但是在return語句中,把指針變量str裡面的值(等於字符串"hello"存放處的地址)送到“返回值寄存器”中了。

動態變量str不存在了,但常量區中的字符串"hello"還存在。主程序根據返回的地址就可以找到該字符串。

程序四:

int main()
{
    char *p;
    char *fun(void);
    p=fun();
    printf("%x\n",p);
    printf("%s\n",p);
    return 0;
}
char* fun(void)
{
//    char str[]={'a','b','c','d','e','f','\0'};
    char str[]="hello";
    printf("%x\n",str);
    return str;
}
//不能正確返回

char str[]="hello"; 是在動態變量區中開辟了可以容納6個字符的數組,數組名叫str。同時將字符串"hello"(原存放於常數空間)拷貝到這個數組空間中去作為數組的初始化值。
此時若執行return str; 其中的str是數組名。C語言規定,表達式中如果是數組名,則該表達式的值就等於這個數組的地址。所以返回的是這個數組的地址,請注意:並不是字符串常量"hello"的地址!而函數結束時,雖然常數空間並不破壞,但這個數組空間是破壞了的,而你返回的卻不是常數空間裡的地址而正是已經破壞了的數組的地址。

而char *str="hello"; 是在動態變量區中開辟了一個可以存放一個指針值的變量,名叫str。同時將原存放於常數空間的字符串"hello"的地址賦給這個指針變量作為初始值。
此時若執行return str; 其中的str是指針變量名。C語言規定,表達式中如果是變量名,則該表達式的值就等於這個變量的值(指針變量的值就是地址)。所以返回的是變量str的值,而變量str的值就等於字符串常量"hello"的地址。而函數結束時,變量str破壞了的,但常數空間中的字符串並不破壞。主程序根據返回的地址就可以找到該字符串。

【總結】

常規程序中,函數返回的指針通常應該是:

(1)指向靜態(static)變量;

(2)指向專門申請分配的(如用malloc)空間;

(3)指向常量區(如指向字符串"hello");

(4)指向全局變量;

(5)指向程序代碼區(如指向函數的指針)。

除這5項以外,其它怪技巧不提倡。

函數內的變量,沒有關鍵字static修飾的變量的生命周期只在本函數內,函數結束後變量自動銷毀。當返回為指針的時候需要特別注意,因為函數結束後指針所指向的地址依然存在,但是該地址可以被其他程序修改,裡面的內容就不確定了,有可能後面的操作會繼續用到這塊地址,有可能不會用到,所以會出現時對時錯的情況,如果需要返回一個指針而又不出錯的話只能調用內存申請函數

返回結構體:

#include <stdio.h>
typedef struct {
            int a;
            int b;
            int c;
        }str;
str change(str s)
{
    s.a += 1;
    s.b += 1;
    s.c += 1;
    return s;
}
int main(void)
{
    str s1, s2;
    s1.a = 1;
    s1.b = 1;
    s1.c = 1;
    s2 = change(s1);
    printf("s1.a = %d\ts1.b = %d\ts1.c = %d\n",s1.a, s1.b, s1.c);
    printf("s2.a = %d\ts2.b = %d\ts2.c = %d\n",s2.a, s2.b, s2.c);
    return 0;
}

//可以返回
  1. 上一頁:
  2. No
Copyright © 程式師世界 All Rights Reserved