1. 程式人生 > >指標與字串、指標與函式

指標與字串、指標與函式

標題1、 指標與字串的千絲萬縷

由於在C語言中,是通過字元陣列來儲存字串的,因而前面通過指標對一維陣列和二維陣列的操作方法,同樣適用於字串。其實,對字串的操作最好採用字串操作函式。

#include<stdio.h>
int main()
{
	char name[12],*p;
	p=name;
	gets(p);
	puts(p); 
	return 0;
}
再例如:char *p=”hello”;等價於char *p; p=”hello”。
        它的意思是把:hello串在記憶體中的首地址賦值給p。
我們已經講過,如果要儲存和處理我們班49個同學的姓名,可以定義一個二維陣列,假設48個同學的姓名只佔6個位元組,因而第二維的大小為7即可,只有一個同學是少數民族,她的姓名需要佔19個位元組,因而需要給它分配至少20個位元組的單元才能存放,為此,整個二維陣列的第二維的大小必須為20個位元組。char name[49][20];
    顯然,這樣會造成記憶體的浪費:48*13個位元組的空間是無用的。如果隨著問題規模的增大,這個浪費會更大,有沒有一種辦法,當需要多大空間的時候就分配多大的空間,字元指標陣列就可以解決這個問題。
    char *name[3]={"hello","lcy","hahahahahahaha"};
這樣定義之後,”hello”在記憶體中的首地址賦值給name[0],同理”lcy”在記憶體中的首地址賦值給name[1],"hahahahahahaha"在記憶體中的首地址賦值給name[2]。
    有同學會問:如果我們班同學的姓名都這樣初始化的話,感覺也挺麻煩的:char* name[49]={“111”,”222”,,,,,,,,,,,,,,,,};
姓名能不能在程式中輸入呢?

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	char *name[49], s[20];
	int i;
	for(i=0;i<49;i++)
	{
		gets(s);
		name[i]=(char*)malloc(strlen(s)+1);
		if(name[i]!=NULL)
        strcpy(name[i],s);
    }
    for(i=0;i<49;i++)
        puts(name[i]);
	for(i=0;i<49;i++)
		    free(name[i]);
	return 0;
}

因為malloc函式分配的記憶體空間是在堆區上分配的,程式結束後,系統不會將其自動釋放,需要程式設計師自己管理,C提供了free函式來釋放記憶體。

標題2 :指標與函式

1. 指標作為函式引數

指標作為函式引數有兩種形式:
(1)指標變數作為函式引數。前面我們講過的swap函式,就是採用指標變數作為函式引數,才能通過swap函式交換實參的值。
(2)陣列作為函式引數。前面我們講解一維陣列時,如果採用子函式形式來描述氣泡排序和選擇排序時,就是採用了陣列作為函式形參。這裡不再贅述。
下面我們看一下字串的連線函式來加深記憶吧。
(1)採用指標變數作為函式形參:

#include<stdio.h>
void connect_string(char *from,char *to)
{
	while(*from!='\0')
		from++;
	while(*to!='\0')
		*from++=*to++;
	*from='\0';
}
int main()
{
	char str1[50],str2[50];
	gets(str1);
	gets(str2);
	connect_string(str1,str2);
	puts(str1);
	return 0;
}

(2)採用陣列作為函式形參

#include<stdio.h>
#include<string.h>
void connect_string(char from[],char to[])
{
	int i,j;
	for(i=strlen(from),j=0;j<strlen(to);i++,j++)
		from[i]=to[j];
	from[i]='\0';
}
int main()
{
	char str1[50],str2[50];
	gets(str1);
	gets(str2);
	connect_string(str1,str2);
	puts(str1);
	return 0; 
}

2. 返回指標的函式(也稱為指標函式)

函式的返回值可以是int、double、char、int、void,C語言還允許函式的返回值是一個指標(地址)。

#include<stdio.h>
char *strchr(char *s,char ch)
{
	while(*s!='\0')
		if(*s==ch) return s;
		else s++;
}
int main()
{
	char *p=NULL,ch,s[]="hello,big data!";
	ch=getchar();
	p=strchr(s,ch);
	if(p)
		{
		    printf("%c's position is:%x\n",ch,p);
		    printf("%c's position is:%d\n",ch,p-s+1);
		}
	else
		printf("%c isn't exist!\n");
	return 0;
}

該程式的功能,輸出某個字元(該字元可通過鍵盤輸入)在字串中的位置。
在這裡插入圖片描述

3. 指向函式的指標

如果在程式中定義了一個函式,在編譯時,編譯器為該函式程式碼分配了一段儲存空間,這段儲存空間的首地址可以用函式名來描述。因而,可以把這個首地址賦給一個指標變數,使得該指標變數指向該函式,把這種指向函式的指標變數稱為:函式指標變數或者函式指標。

 #include<stdio.h>
    int func(int a,int b)
    {
        return a+b;
    }
    int main()
    {
    	int result;
    	int(*p)(int,int);
    	p=func;
    	result=(*p)(3,5);
    	printf("%d\n",result);
    	return 0;
    }

其中,p=func; //讓指標變數指向了func函式的首地址
      result=(*p)(3,5);//通過指標變數p來呼叫函式

函式指標可作為函式引數。

用函式名來呼叫函式,只能呼叫指定的函式。而通過函式指標變數呼叫函式就比較靈活了,可以根據不同情況先後呼叫不同的函式。

#include<stdio.h>
int add(int a,int b)
{
    return a+b;
}
int minus(int a,int b)
{
    return a-b;
}
int xc(int a,int b)
{
    return a*b;
}
int func(int(*p)(int,int),int b,int n)
{
    int result=0,i;
    for(i=0;i<n;i++)
        result+=(*p)(i,b);
    return result;
}
int main()
{
	int result;
	result=func(add,1,10);
	printf("%d\n",result);
	result=func(minus,1,10);
	printf("%d\n",result);
	result=func(xc,1,10);
	printf("%d\n",result);
	return 0;
}

4. 帶引數的main函式

前面使用的main都是無參的,實際上該函式也可以接收引數。main()函式是程式的入口,通常用來接收來自系統的引數。argc表示在命令列中輸入的引數個數,argv為字元指標陣列,其各個元素值為命令列中各字串的首地址。

#include<stdio.h>
int main(int argc,char* argv[])
{
    int i;
    printf("%d\n",argc);
    for(i=0;i<argc;i++)
        puts(argv[i]);
    return 0;
}

在這裡插入圖片描述

5、 其它知識

週二實驗課,黎龍洋同學問了一個memset函式的問題,問是不是進行初始化的。其實,還有很多對記憶體進行操作的函式:熟悉的malloc、free,還有memcpy、memmove和memcmp等等。用到的時候查閱下資料,不同的函式均有不同的用途。C++提供了new來進行記憶體空間的動態分配,我感覺也非常方便。

#include<iostream>
using namespace std;
int main()
{
    int *p,n,i;
    cin>>n;
    p=new int[n]{0}; //初始化
    for(i=0;i<n;i++)
        cout<<*(p+i)<<" ";
cout<<endl;
delete [] p; 
    return 0;
}

需要注意的是:p=new int[n]{0}; 動態開闢一個含n個int的無名陣列空間,把該空間的首地址賦給P,陣列中的元素均初始化為0。

delete [] p; //釋放空間,因為p指向的是陣列,因而需要加上[ ]。