我一下討論的都是在不用return把值進行返回的情況, 也就是說用指針的情況。
很簡單就是指針和引用,引用在新版本的c裏面也有包含,可以使用。
系統xp+ide用的 vc6.0:
要把一個值通過調用函數改變,可以用指針和引用,這個值可以是int int *,char char*,或者說是結構體,結構體也有不同的情況,比如說,
結構裏面有結構體指針和沒有的情況,這裏我將就我的經歷寫一下。
先看看人家的比較好的說法:
void func1( MYCLASS *&pBuildingElement );
仔細看一下這種聲明方式,確實有點讓人迷惑。在某種意義上,"*"和"&"是意思相對的兩個東西,把它們放在一起有什麼意義呢?。爲了
理解指針的這種做法,我們先複習一下C/C++編程中無所不在的指針概念。我們都知道MYCLASS*的意思:指向某個對象的指針,此對象的類型爲
MYCLASS。 void func1(MYCLASS *pMyClass);
例如: MYCLASS* p = new MYCLASS;
或者你也可以用malloc函數在c下面申請一片內存地址。
func1(p);
上面這段代碼的這種處理方法想必誰都用過,創建一個MYCLASS對象,然後將它傳入func1函數。現在假設此函數要修改pMyClass: void
func1(MYCLASS *pMyClass)
{
DoSomething(pMyClass);
pMyClass = // 其它對象的指針
}
第二條語句在函數過程中只修改了pMyClass的值。並沒有修改調用者的變量p的值。如果p指向某個位於地址0x008a00的對象,當func1返
回時,它仍然指向這個特定的對象。(除非func1有bug將堆弄亂了,完全有這種可能。)
現在假設你想要在func1中修改p的值。這是你的權利。調用者傳入一個指針,然後函數給這個指針賦值。以往一般都是傳雙指針,即指針
的指針,例如,CMyClass**。 MYCLASS* p = NULL;
func1(&p);
void func1(MYCLASS** pMyClass);
{
*pMyClass = new MYCLASS;
……
}
調用func1之後,p指向新的對象。
如果你理解指針的指針,那麼你肯定就理解指針引用,因爲它們完全是一回事。如果你象下面這樣聲明函數:
void func1(MYCLASS *&pMyClass);
{
pMyClass = new MYCLASS;
……
}
其實,它和前面所講得指針的指針例子是一碼事,只是語法有所不同。傳遞的時候不用傳p的地址&p,而是直接傳p本身:
MYCLASS* p = NULL;
func1(p);
在調用之後,p指向一個新的對象。一般來講,引用的原理或多或少就象一個指針,從語法上看它就是一個普通變量。所以只要你碰到*&
,就應該想到**。也就是說這個函數修改或可能修改調用者的指針,而調用者象普通變量一樣傳遞這個指針,不使用地址操作符&。
下面是我的編程經歷,也可以算是經驗吧:
接着我們對int 和 結構體的情況討論,一般char的都是處理字符串很簡單的。
要改變值可以如下,指針和引用:
一般的對int改變值其實可以就可以只用一個*,用兩個指針和引用就是爲了加強理解,我門看看:
下面的是用指針的測試函數
1:
void function(int *ref) //單指針的改變值的函數
{
//ref=(int *)malloc(sizeof(int));這句不能用,如果用了傳入的地址無效,因爲這裏又重新分配了一個地址,那麼原來傳入的地址
沒有被操作。
*ref=100;
}
int main() //測試函數,main();
{
int *x;
x=(int *)malloc(4);//先分配地址,要不後面給沒有初始化的指針賦值會出現segments fault。
*x=200;
function(x);
printf("*x=%d/n",*x);
}
當然了main函數也可以這麼設計:
int main() //測試函數,main();
{
int x;
function(&x);
printf("x=%d/n",x);
}
2:
下面給出雙指針的使用方法:
void function(int **p) //雙指針的函數
{
*p=(int *)malloc(sizeof(int));//用了或者不用都可以了,用了也可以改變傳入的地址上的值,這個我就不曉得爲什麼了。
//但是不用當然是可以的,因爲調用之前定義的指針要分配地址的,傳入的地址沒有segments
fault就可以了。我不用的。
//記住一點對與雙指針的地址操作都是對*p來的,不是對p,而單指針就是上面的函數地址操作就是
對p來的。呵呵。上面的兩個function可以說是很通用了。
**p=100;
}
int main() //測試函數,main();
{
int *x;
x=(int *)malloc(4);//先分配地址,要不後面給沒有初始化的指針賦值會出現segments fault。
*x=200;
function(&x);
printf("x=%d/n",*x);
}
看完了指針就看引用了,&這個符號是一個二義符號,不可以認爲是取地址的。
看函數:
3:
void function(int &refval)
{
refval=100;
}
int main()
{
int x=200;
function(x);
//當然,如下調用也可以。但這樣做就失去引入"引用"的原本意義了,不過引用就是引用,作用對象refval的值和地址都和x的值和地址一樣
了,可以認爲是捆綁式的了。呵呵
printf("x=%d/n",x);
return 0;
}
4:
再看指針的引用:其實指針的引用可以理解成雙指針,只是其地址式p而不是*p,呵呵。
看這個程序:程序比較多呵呵
#include <stdio.h>
#include <malloc.h>
void function(int *&ref)
{
//ref=(int *)malloc(sizeof(int));//這裏同雙指針,分配或者不分配都是可以的。
*ref=100;
}
int main()
{
int *x; //要這種定義纔可以使用。
x=(int *)malloc(4);
*x=200;
function(x);
printf("x=%d/n",*x);
return 0;
}
//這裏也有點研究的必要,如果像下面這個給出main函數:
int main()
{
int x=300;
function(&x);
printf("x=%d/n",x);
}
編譯通過不了的,很簡單,指針的引用其實本質應該式雙指針,上面的main中的值是給單指針的賦值,顯然也是不可以的。錯誤提示如下:
D:/hehe/hehe/yinyong/yin.cpp(22) : error C2664: 'function' : cannot convert parameter 1 from 'int *' to 'int *& '
對於結構體,有兩種情況,一種就是結構體裏面沒有結構體指針的,要傳值或者說要通過調用函數改變他的值,就像上面的int型的使用方法,
這裏就只說說其中的初始化,改變值是一樣的:
先給定結構體:
typedef struct stack {
int data;
char *p;
}st,*Ls;
開始已經說了,不用return方法,就用傳值的方法:
1:
如果在main函數裏面定義成:st list;那麼初始化就是:這裏應該知道,變量的引用就是變量的單指針一樣。
void set(st &list)
{
list.data=100;
list.p="asdf";
}
結構體定義:st list;
函數調用是:
set(list);
2:
如果在main函數裏面定義成:st *list;那麼初始化就是:
void set(st *list)
{
list->data=100;
list->p="asdf";
}
結構體定義:st list;
函數調用是:
set(&list);
或者:
結構體定義:st *list;
函數調用是:
set(list);
這種情況我覺得不要使用指針的引用。
另外一種就是結構體裏面還有結構體指針,如下定義結構體:
typedef struct stack {
int data;
struct stack *next;
}st,*ls;
初始化的方法有幾種,跟聲明變量有關:
1:雙指針法:
void init(st **head){
(*head)=(st *)malloc(sizeof(st)); //也可以不分配地址,因爲在每次main傳值時,都必須先分配地址空間
(*head)->next=null;
}
聲明結構體變量的時候,一般這麼定義,
st *head;
調用函數的時候這麼用:
init(st &head);
2:單指針法
這個方法要使用到返回傳值,我們不研究,當然了寫一下:
st *InitializeList(st *plist)
{
// plist=(st *)malloc(sizeof (st)); //也可以不用。
plist = NULL;
return plist;
}
3另一種雙指針法
其實這種只是在定製結構體類型的時候把st定義成了*ls,然後用ls來定義結構體。
如下:
void InitializeList(ls *plist)
{
//plist=malloc(sizeof (List)); //可以不用。
*plist = NULL;
}
聲明結構體變量的時候,一般這麼定義,
st *head;
或者
ls head;
調用函數的時候都是這麼用:
InitializeList(&head);
這裏我要說的,其實在初始化和使用的時候跟雙指針一個樣子的,使用的是*p而不是p,把他的地址賦值給其他的結構體的時候也要用*plist,
具體的可以看下面的程序;
struct film
{
char title[TSIZE];
int rating;
};
typedef struct film Item;
typedef struct node
{
Item item;
struct node * next;
} Node;
typedef Node * List;
bool AddItem(Item item, List * plist)
{
Node * pnew;
Node * scan =* plist; //賦地址的時候用* plist
pnew = (Node *) malloc(sizeof(Node));
if (pnew == NULL)
return false; /* quit function on failure */
pnew= CopyToNode(item, pnew);
pnew->next = NULL;
if (scan == NULL) /* empty list, so place */
*plist = pnew; /* pnew at head of list */ //賦地址的時候用* plist
else
{
while (scan->next != NULL)
scan = scan->next; /* find end of list */
scan->next = pnew; /* add pnew to end */
}
return true;
}
4:
最後了,就是指針的引用來初始化內含結構體指針的結構體:
void InitializeList(st *&plist)
{
plist=(st *)malloc(sizeof (st)); //也可以不用。
plist->next = NULL;
}
這裏其實跟上面講到的指針的引用是一樣的,跟雙指針差不多,但是使用的時候用plist,plist->next而不是*plist,(*plist)->next。
聲明結構體爲:
st *plist;
調用函數:
InitializeList(plist);
到此,我所遇到的一些指針和指針的引用都列舉出來了。有什麼不對,大家可以指點一下哈。
下面是我的一個指針的引用的具體的程序可以通過:
#include <stdio.h>
#include <malloc.h>
#define null 0
typedef struct linknode
{
char data;
struct linknode *next;
}listack;
void initstack(listack *&s)//初始化
{
s=(listack *)malloc(sizeof(listack));
s->next=null;
}
void clear(listack *&s){//釋放堆棧
listack *p=s->next;
while(p!=null)
{
free(s);
s=p;
p=p->next;
}
}
int length(listack *s){//顯示堆棧長度
int i=0;
listack *p;
p=s->next;
while(p!=null)
{
i++;
p=p->next;
}
return i;
}
int empty(listack *s){//空?
return (s->next==null);
}
void push(listack *&s,char e){//入堆棧
listack *p;
p=(listack *)malloc(sizeof(listack));
p->data=e;
p->next=s->next;
s->next=p;
}
int pop(listack *&s,char e){//出堆棧
listack *p;
if(s->next==null)
return 0;
p=s->next;
e=p->data;
s->next=p->next;
free(p);
return 1;
}
int gettop(listack *&s,char e){//顯示第一個數據
if(s->next==null)
return 0;
e=s->next->data;
return 1;
}
void display(listack *s){//顯示所有數據
listack *p=s->next;
while(p!=null){
printf("%c",p->data);
p=p->next;
}
puts("");
}
int main()
{
char e;
listack *s;
puts("初始化堆棧/n");
initstack(s);//指針的引用
printf("戀棧爲%s/n",((empty(s))?"empty":"no empty"));
push(s,'a');
push(s,'b');
push(s,'c');
push(s,'d');
push(s,'f');
push(s,'e');
printf("戀棧爲%s/n",(empty(s)?"empty":"no empty"));
printf("lenth=%d/n",length(s));
puts("xianshi/n");
display(s);
printf("out stack!/n");
while(!empty(s)){
pop(s,e);
printf(" %c",e);
}
puts("");
printf("戀棧爲%s/n",((empty(s))?"empty":"no empty"));
printf("delete the stack/n");
clear(s);
return 0;
}