A. 有沒有在PowerShell中的函數指針或函數數組
指針數組是指針的數組,把這句話重復三遍
這個數組里放的滿滿的都是指針
數組指針是一個指針,這個指針指向一個數組
同理函數指針指向一個函數,只是個變數
指針函數是指帶指針的函數,即本質是一個函數
int *f(x,y);
是很繞人
B. 調用一個動態庫中的函數,這個函數有一個參數是結構體指針,我如何使用這個指針
你就也定義一個形參中的結構體指針接收傳過來的結構體指針就OK啦
形參中的結構體指針改變?這什麼意思?
給你看個例子吧:
struct node *creat(struct node *l)
{
struct node *head;
head=l;
return head;
}
你是這樣嗎~
C. 簡單的shell編程
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFERSIZE 80
extern char *get_current_dir_name(void);
extern char *getenv(const char *name);
extern pid_t waitpid(pid_t pid, int *status, int options);
char buffer[BUFFERSIZE+1];
main()
{
char *path, *arg[10], *input;
int li_inputlen, is_bj, is_back, i, j, k, pid, status;
char lc_char;
while (1){
/* initiations */
is_bj = 0; /*redirection flag*/
is_back = 0; /*background*/
/* shell prompt */
path = get_current_dir_name();
printf("%s>$",path);
/*開始獲取輸入*/
li_inputlen = 0;
lc_char = getchar();
while (lc_char !='\n'){
if(li_inputlen < BUFFERSIZE)
buffer[li_inputlen++] = lc_char;
lc_char = getchar();
}
/*命令超長處理*/
if (li_inputlen >= BUFFERSIZE){
printf("Your command is too long! Please re-enter your command!\n");
li_inputlen = 0; /*reset */
continue;
}
else
buffer[li_inputlen] = '\0';/*加上串結束符號,形成字串*/
/*將命令從緩存拷貝到input中*/
input = (char *) malloc(sizeof(char) * (li_inputlen+1));
strcpy(input,buffer);
/* 獲取命令和參數並保存在arg中*/
for (i = 0,j = 0,k = 0;i <= li_inputlen;i++){
/*管道和重定向單獨處理*/
if (input[i] == '<' || input[i] == '>' || input[i] =='|'){
if (input[i] == '|')
pipel(input,li_inputlen);
else
redirect(input,li_inputlen);
is_bj = 1;
break;
}
/*處理空格、TAB和結束符。不用處理『\n',大家如果仔細分析前面的獲取輸入的程序的話,
*不難發現回車符並沒有寫入buffer*/
if (input[i] == ' ' || input[i] =='\t' || input[i] == '\0'){
if (j == 0) /*這個條件可以略去連在一起的多個空格或者tab*/
continue;
else{
buffer[j++] = '\0';
arg[k] = (char *) malloc(sizeof(char)*j);
/*將指令或參數從緩存拷貝到arg中*/
strcpy(arg[k],buffer);
j = 0; /*准備取下一個參數*/
k++;
}
}
else{
/*如果字串最後是『&',則置後台運行標記為1*/
if (input[i] == '&' && input[i+1] == '\0'){
is_back = 1;
continue;
}
buffer[j++] = input[i];
}
}
free(input);/*釋放空間*/
/*如果輸入的指令是leave則退出while,即退出程序*/
if (strcmp(arg[0],"leave") == 0 ){
printf("bye-bye\n");
break;
}
/*如果輸入的指令是about則顯示作者信息,同時結束本條命令的解析過程*/
if (strcmp(arg[0]," about") == 0 ){
printf("right by shike,shike13@163.com\n");
continue;
}
if (is_bj == 0){ /*非管道、重定向指令*/
/*在使用xxec執行命令的時候,最後的參數必須是NULL指針,
*所以將最後一個參數置成空值*/
arg[k] = (char *) 0;
/*判斷指令arg[0]是否存在*/
if (is_fileexist(arg[0]) == -1 ){
printf("This command is not found?!\n");
for(i=0;i<k;i++)
free(arg[i]);
continue;
}
/* fork a sub-process to run the execution file */
if ((pid = fork()) ==0) /*子進程*/
execv(buffer,arg);
else /*父進程*/
if (is_back == 0) /*並非後台執行指令*/
waitpid(pid,&status,0);
/*釋放申請的空間*/
for (i=0;i<k;i++)
free(arg[i]);
}
}
}
int is_fileexist(char *comm)
{
char *path,*p;
int i;
i = 0;
/*使用getenv函數來獲取系統環境變數,用參數PATH表示獲取路徑*/
path = getenv("PATH");
p = path;
while (*p != '\0'){
/*路徑列表使用『:』來分隔路徑*/
if (*p != ':')
buffer[i++] = *p;
else{
buffer[i++] = '/';
buffer[i] = '\0';
/*將指令和路徑合成,形成pathname,並使用access函數來判斷該文件是否存在*/
strcat(buffer,comm);
if (access(buffer,F_OK) == 0) /*文件被找到*/
return 0;
else
/*繼續尋找其它路徑*/
i = 0;
}
p++;
}
/*搜索完所有路徑,依然沒有找到則返回-1*/
return -1;
}
int redirect(char *in,int len)
{
char *argv[30],*filename[2];
pid_t pid;
int i,j,k,fd_in,fd_out,is_in = -1,is_out = -1,num = 0;
int is_back = 0,status=0;
/*這里是重定向的命令解析過程,其中filename用於存放重定向文件,
*is_in, is_out分別是輸入重定向標記和輸出重定向標記*/
for (i = 0,j = 0,k = 0;i <= len;i++){
if (in[i]==' '||in[i]=='\t'||in[i]=='\0'||in[i] =='<'||in[i]=='>'){
if (in[i] == '>' || in[i] == '<'){
/*重定向指令最多'<','>'各出現一次,因此num最大為2,
*否則認為命令輸入錯誤*/
if (num < 3){
num ++;
if (in[i] == '<')
is_in = num - 1;
else
is_out = num - 1;
/*處理命令和重定向符號相連的情況,比如ls>a*/
if (j > 0 && num == 1) {
buffer[j++] = '\0';
argv[k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[k],buffer);
k++;
j = 0;
}
}
else{
printf("The format is error!\n");
return -1;
}
}
if (j == 0)
continue;
else{
buffer[j++] = '\0';
/*尚未遇到重定向符號,字元串是命令或參數*/
if (num == 0){
argv[k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[k],buffer);
k++;
}
/*是重定向後符號的字元串,是文件名*/
else{
filename[status] = (char *) malloc(sizeof(char)*j);
strcpy(filename[status++],buffer);
}
j = 0; /*initate*/
}
}
else{
if (in[i] == '&' && in[i+1] == '\0'){
is_back = 1;
continue;
}
buffer[j++] = in[i];
}
}
argv[k] = (char *) 0;
if (is_fileexist(argv[0]) == -1 ){
printf("This command is not founded!\n");
for(i=0;i<k;i++)
free(argv[i]);
return 0;
}
if ((pid = fork()) ==0){
/*存在輸出重定向*/
if (is_out != -1)
if((fd_out=open(filename[is_out],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1){
printf("Open out %s Error\n",filename[is_out]);
return -1;
}
/*存在輸入重定向*/
if (is_in != -1)
if((fd_in=open(filename[is_in],O_RDONLY,S_IRUSR|S_IWUSR))==-1){
printf("Open in %s Error\n",filename[is_out]);
return -1;
}
if (is_out != -1)
/*使用p2函數將標准輸出重定向到fd_out上,p2(int oldfd,int newfd)實現的
*是把oldfd所指的文件描述符復制到newfd。若newfd為一已打開的文件描述詞,
*則newfd所指的文件會先被關閉,p2復制的文件描述詞與原來的文件描述詞
*共享各種文件狀態*/
if(p2(fd_out,STDOUT_FILENO)==-1){
printf("Redirect Standard Out Error\n");
exit(1);
}
if (is_in != -1)
if(p2(fd_in,STDIN_FILENO)==-1){
printf("Redirect Standard Out Error\n");
exit(1);
}
execv(buffer,argv);
}
else
if (is_back == 0) /*run on the TOP*/
waitpid(pid,&status,0);
for (i=0;i<k;i++)
free(argv[i]);
if (is_in != -1){
free(filename[is_in]);
close(fd_in);
}
if (is_out != -1){
free(filename[is_out]);
close(fd_out);
}
return 0;
}
int pipel(char *input,int len)
{
char *argv[2][30];
int i,j,k,count,is_back = 0;
int li_comm = 0,fd[2],fpip[2];
char lc_char,lc_end[1];
pid_t child1,child2;
/*管道的命令解析過程*/
for (i = 0,j = 0,k = 0;i <= len;i++){
if (input[i]== ' ' || input[i] == '\t' || input[i] == '\0' || input[i] == '|'){
if (input[i] == '|' ) /*管道符號*/
{
if (j > 0)
{
buffer[j++] = '\0';
/*因為管道連接的是兩個指令,所以用二維數組指針來存放命令和參數,
*li_comm是表示第幾個指令*/
argv[li_comm][k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[li_comm][k++],buffer);
}
argv[li_comm][k++] = (char *) 0;
/*遇到管道符,第一個指令完畢,開始准備接受第二個指令*/
li_comm++;
count = k;
k=0;j=0;
}
if (j == 0)
continue;
else
{
buffer[j++] = '\0';
argv[li_comm][k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[li_comm][k],buffer);
k++;
}
j = 0; /*initate*/
}
else{
if (input[i] == '&' && input[i+1] == '\0'){
is_back = 1;
continue;
}
buffer[j++] = input[i];
}
}
argv[li_comm][k++] = (char *) 0;
if (is_fileexist(argv[0][0]) == -1 ){
printf("This first command is not found!\n");
for(i=0;i<count;i++)
free(argv[0][i]);
return 0;
}
/*指令解析結束*/
/*建立管道*/
if (pipe(fd) == -1 ){
printf("open pipe error!\n");
return -1;
}
/*創建第一個子進程執行管道符前的指令,並將輸出寫到管道*/
if ((child1 = fork()) ==0){
/*關閉讀端*/
close(fd[0]);
if (fd[1] != STDOUT_FILENO){
/*將標准輸出重定向到管道的寫入端,這樣該子進程的輸出就寫入了管道*/
if (p2(fd[1],STDOUT_FILENO) == -1){
printf("Redirect Standard Out Error\n");
return -1;
}
/*關閉寫入端*/
close(fd[1]);
}
execv(buffer,argv[0]);
}
else{ /*父進程*/
/*先要等待寫入管道的進程結束*/
waitpid(child1,&li_comm,0);
/*然後我們必須寫入一個結束標記,告訴讀管道進程數據到這里就完了*/
lc_end[0] = 0x1a;
write(fd[1],lc_end,1);
close(fd[1]);
if (is_fileexist(argv[1][0]) == -1 ){
printf("This command is not founded!\n");
for(i=0;i<k;i++)
free(argv[1][i]);
return 0;
}
/*創建第二個進程執行管道符後的指令,並從管道讀輸入流 */
if ((child2 = fork()) == 0){
if (fd[0] != STDIN_FILENO){
/*將標准輸入重定向到管道讀入端*/
if(p2(fd[0],STDIN_FILENO) == -1){
printf("Redirect Standard In Error!\n");
return -1;
}
close(fd[0]);
}
execv(buffer,argv[1]);
}
else /*父進程*/
if (is_back == 0)
waitpid(child2,NULL,0);
}
for (i=0;i<count;i++)
free(argv[0][i]);
for (i=0;i<k;i++)
free(argv[1][i]);
return 0;
}
以前寫的,好像一些細節不一樣,不明白的地方,發郵件給我,shike13@163.com
D. 直接調用函數與通過函數指針調用有什麼不一樣
函數指針是指向函數的指針變數。也就是說,它是一個指針變數,而且該指針指向一個函數。
對於指針變數來說,它的值是它指向的變數的地址。舉個例子:指針變數pi是指向一個整型變數i的指針,則變數i的地址 &i 就是指針變數pi的值。也就是說整型變數指針指向一個整型變數,而整型變數指針的值就是它所指的整型變數的地址。與其它類型指針變數一樣,函數指針變數的值就是它指向的函數的地址。
那麼什麼是函數的地址呢?
我們首先來看函數調用是怎麼回事。在程序運行時,一個函數佔用一段連續的內存。當調用一個函數時,實際上是跳轉到函數的入口地址,執行函數體的代碼,完成後返回。
函數指針指向一個函數的入口地址,也就是函數存儲空間的首地址。
在C語言中,數組名代表數組的首地址,同樣函數名代表了函數的首地址,因此在賦值時,直接將函數指針指向函數名就行了。
函數指針的定義
一般,函數指針的定義格式為:
函數類型 (*指針變數名)(形參列表);
「函數類型」說明函數的返回類型,由於「()」的優先順序高於「*」,所以指針變數名外的括弧必不可少,後面的「形參列表」表示指針變數指向的函數所帶的參數列表。
例如:對於函數int f(int a),我們定義一個指向該函數的函數指針fp,採用如下格式:
int (*fp)(int a);
函數指針的賦值
前面我們已經講到,在C語言中,函數名代表了函數的首地址,因此在賦值時,直接將函數名賦值給函數指針就可以了。
例如:
int func(int x); //聲明一個函數
int (*fp)(int x); //定義一個函數指針
fp = func; //將func函數的首地址賦值給指針fp
賦值時函數func不帶括弧,也不帶參數,由於func代表函數的首地址,因此經過賦值以後,指針就指向函數func(x)的代碼的首地址。
通過函數指針調用函數
與其它指針變數相類似,如果指針變數pi是指向某整型變數i的指針,則*pi等於它所指向的變數i;如果pf是指向某浮點型變數f的指針,則*pf就等價於它所指的變數f。同樣地,fp是指向函數func(x)的指針,則*fp就代表它所指向的函數func。所以在執行了fp = func;之後,(*fp)和func代表同一函數。
由於函數指針指向存儲區中的某個函數,因此可以通過函數指針調用相應的函數。
用函數指針調用函數由三步組成:
首先,定義函數指針變數。
例如:int (*fp)(int x);
然後,給函數指針變數賦值。
例如:fp = func; (func(x)必須要先有定義)
最後,用(*指針變數)(參數表);調用函數。
例如:(*fp)(x);(x必須先賦值)。
在這里,(*fp)(x);一般寫成fp(x); fp(x)是標准C++的寫法,(*fp)(x);是兼容C語言的標准寫法。
總結以上知識,舉例說明
到目前為止,相信您已經簡單了解了函數指針,下面我們舉一個簡單的、完整的程序進行說明。
E. Linux.,,,,,,,shell語言,
參數type可使用「r」代表讀取,「w」代表寫入。依照此type值,popen()會建立管道連到子進程的標准輸出設備或標准輸入設備,然後返回一個文件指針。隨後進程便可利用此文件指針來讀取子進程的輸出設備或是寫入到子進程的標准輸入設備中。此外,所有使用文件指針(FILE*)操作的函數也都可以使用,除了fclose()以外。 返回值:若成功則返迴文件指針,否則返回NULL,錯誤原因存於errno中。 注意:在編寫具SUID/SGID許可權的程序時請盡量避免使用popen(),popen()會繼承環境變數,通過環境變數可能會造成系統安全的問題。 例:C程序popentest.c內容如下: #include<stdio.h> main() { FILE * fp; charbuffer[80]; fp=popen(「~/myprogram/test.sh」,」r」); fgets(buffer,sizeof(buffer),fp); printf(「%s」,buffer); pclose(fp); } 執行結果如下: xiakeyou@ubuntu:~/myprogram$ vim popentest.c xiakeyou@ubuntu:~/myprogram$ gcc popentest.c -o popentest xiakeyou@ubuntu:~/myprogram$ ./popentest /home/d/e/xiakeyou xiakeyou@ubuntu:~/myprogram$ 只是偶能力可能有點有限,沒有太看懂。直接用system()倒是腳本可是執行,只是返回值卻是一塌糊塗,試了多次也沒有找到什麼規律。不免又看了一下上面的那篇博文,得到一些啟發,可以這樣來實現: 先將腳本的返回值利用 echo > XXXXX 輸出到一個本地文件中 當需要這個返回值是,可是通過C語言的文件操作函數來直接從文件中讀取 後來一想,這應該就是上文中POPEN的實現方法! C程序調用shell腳本共有三種法子 :system()、popen()、exec系列函數 system() 不用你自己去產生進程,它已經封裝了,直接加入自己的命令exec 需要你自己 fork 進程,然後exec 自己的命令 popen() 也可以實現執行你的命令,比system 開銷小 1)system(shell命令或shell腳本路徑); system()會調用fork()產生 子歷程,由子歷程來調用/bin/sh-c string來履行 參數string字元串所代表的命令,此命令履行 完後隨即返回原調用的歷程。在調用system()期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT 信號則會被漠視 。 返回值:如果system()在調用/bin/sh時失敗則返回127,其他失敗原因返回-1。若參數string為空指針(NULL),則返回非零值。 如果 system()調用成功 則最後會返回履行 shell命令後的返回值,但是此返回值也有可能為system()調用/bin/sh失敗所返回的127,因 此最好能再反省 errno 來確認履行 成功 。 system命令以其簡略 高效的作用得到很很廣泛 的利用 ,下面是一個例子 例:在~/test/目錄下有shell腳本test.sh,內容為 #!bin/bash #test.sh echo hello 在同層目錄下新建一個c文件system_test.c,內容為: #include<stdlib.h> int main() { system("~/test/test.sh"); } 履行 效果 如下: [root@localhost test]$gcc system_test.c -o system_test [root@localhost test]$./system_test hello [root@localhost test]$ 2)popen(char *command,char *type) popen()會調用fork()產生 子歷程,然後從子歷程中調用/bin/sh -c來履行 參數command的指令。參數type可應用 「r」代表讀取,「w」代表寫入。遵循此type值,popen()會建立 管道連到子歷程的標准 輸出設備 或標准 輸入設備 ,然後返回一個文件指針。隨後歷程便可利用 此文件指針來讀取子歷程的輸出設備 或是寫入到子歷程的標准 輸入設備 中。此外,所有應用 文 件指針(FILE*)操作的函數也都可以應用 ,除了fclose()以外。 返回值:若成功 則返迴文件指針,否則返回NULL,差錯 原因存於errno中。
打字不易,如滿意,望採納。