2012-11-26 101 views
1

我一直在寫C約一個星期,所以請耐心等待。我在方法assemble_url中遇到了分段錯誤錯誤,我不知道爲什麼。這裏是我的代碼:使用結構012的seg故障

/** Includes */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <mysql/mysql.h> 

/** Definitions */ 
#define MAX_OPTIONS 32 
#define MAX_ARGS 32 

/** Command option */ 
typedef struct { 
    char *argname; 
    char *value; 
} command_option; 

/** Command */ 
typedef struct { 
    command_option options[MAX_OPTIONS]; 
} command_t; 

/** 
* Prints the arguments passed in in a hashmap format (key => value) 
*/ 
void populate_command(command_t *cmd,int argc,char *argv[]) 
{ 
    int i,j=0; 

    /** Check to see if we have arguments. If argc is equal to 1 than there are no arguments besides the filename */ 
    if(argc>1) 
    { 

     /* Start at position 1, since argv[0] is the filename being called */ 
     for(i=1;i<argc;i++) 
     { 

      /* Head of argv array */ 
      char *arg = argv[i]; 

      /* Create a copy of head for traversal. */ 
      char *c = arg; 

      /* traverse the char array, ensuring we arent dealing with NULL values(c!==NULL) and NULL pointers(*c!=='\0') */ 
      while(*c != '\0' && c != NULL) 
      { 

       /* Were only concerned with parsing the flags and obtaining the flag value. */ 
       if(strchr("-",*c)) 
       { 

        char *key = c; /* Key */ 
        char *value = argv[i+1]; /* Value */ 

        /* ensure we have a value existent for key */ 
        if(strchr("-",*value)) 
        { 
         /** user supplied a key with no value */ 
         break; 
        } 
        command_option *option = &cmd->options[j]; 
        option->argname = key; 
        option->value = value; 

        j++; 

        /* Debug dump */ 
        printf("arg %d: %s -> %s\n",i,option->argname,option->value); 

       }/* end strchr */ 

       /** Increment the traversal array */ 
       c++; 

      }/* end while loop */ 

     }/* end forloop */ 

    }/* endif */ 

}/** end print_args */ 

/** 
* Concatenates two strings and returns the resulting concatenated string 
*/ 
char* concatstring(char *s1,char *s2) 
{ 
    /* Allocate memory for *result. We add 1 to account for the extra byte to store the null character. Strlen accounts for all 
    non-null bytes, so using strlen(s1) + strlen(s2) + 1 ensures that an overflow wont occur. An overflow occurs when 
    the number of bytes being used (in our example, is the addition of strlen for s1 and s2) is more than the number of bytes 
    allocated (in our example, the number of bytes allocated to *result)*/ 
    char *result = malloc(strlen(s1)+strlen(s2)+1); 

    /*Copies the C string pointed by source(s1) into the array pointed by destination(result), including the terminating null character. */ 
    strcpy(result,s1); 

    /* appends a copy of the source string(s2) to the destination string(result). The terminating null character in 
    destination is overwritten by the first character of source, and a null-character is included at 
    the end of the new string formed by the concatenation of both in destination.*/ 
    strcat(result,s2); 

    /* return result */ 
    return result; 

} /** end concatstring */ 

char* assemble_url(command_t *cmd,char *str) 
{ 
    int i,opt_len = sizeof(&cmd->options); 
    for(i=0;i<opt_len;i++) 
    { 
     command_option *option = &cmd->options[i]; 
     char *key = option->argname; 
     char *value = option->value; 
     if(i==0) 
     { 
      str = concatstring(str,key); 
      str = concatstring(str,"="); 
      str = concatstring(str,value); 
     } 
     else 
     { 
      str = concatstring(str,"&"); 
      str = concatstring(str,key); 
      str = concatstring(str,"="); 
      str = concatstring(str,value); 
     } 
    } 
    return str; 
} 

在這個程序中出現什麼如下:

1.在程序名稱和標誌選項/用戶類型,如下列: program -test a -test2 b

2。 /程序解析命令並用選項填充命令結構體。每個選項都有與之相關聯的(值)

3. /程序然後試圖創建與這些選項鍵和值的URL的標誌(argname)和值,諸如http://url/?test=a&test2=b

程序編譯,但我對於指針和引用(我認爲&被稱爲引用)還是新的,所以也許這就是程序錯誤的原因。

任何幫助,非常感謝!另外,如果你看到任何探針或更好的方式來處理assemble_url,請讓我知道(我不認爲它被以最好的方式處理,但就像我說的,我對C編程非常陌生)

謝謝!

+6

現在是學習如何的好時機使用調試器。它將幫助您查明崩潰的位置,讓您檢查函數調用堆棧,並讓您檢查變量以幫助您找出崩潰的可能原因。 –

+1

你知道這個代碼泄漏了多少內存嗎?鏈接的'str = concatstring(str,...)'電話可能是你想要考慮重新考慮的事情,等等。 – WhozCraig

+0

我更新了內容。該程序編譯通過取消註釋assemble_url。我不確定如何使用調試器。 – jkushner

回答

1

這個初始化

int opt_len = sizeof(&cmd->options); 

會給你一個指針&cmd->options的字節大小。這在你所要做的事情的背景下是沒有意義的。

如果要確定元素的數組中的數量(假定它沒有衰減到指針),合適的技術將是

int opt_len = sizeof cmd->options/sizeof *cmd->options; 

在這種情況下opt_lenMAX_OPTIONS值被初始化(這意味着您可以在其位置使用MAX_OPTIONS)。

+0

如何獲得選項數組大小的長度呢? – jkushner

+0

修復後我仍然遇到seg故障。 – jkushner

+1

@jkushner:當然可以。您只需在'populate_command'中初始化數組的'argc'元素。你爲什麼試圖在'assemble_url'中稍後處理它們的所有'MAX_OPTIONS'?如果初始化了'argc'元素,那麼只能在'assemble_url'中使用'argc'元素。 – AnT

1

你有連續字符串的大量內存泄漏。每個調用都會分配一個新的緩衝區,但是您從不費心去釋放它們,並且您放棄了指針,因此沒有機會再次釋放該內存。

這不是段錯誤的原因。

+0

你能協助編程concat_string嗎? – jkushner

+0

只需創建一個長緩衝區,比如1​​024個字節並添加內容(並且始終檢查大小問題)。如果超過大小,你可以重新分配()或返回一個錯誤條件。 – LtWorf

1

因爲你連接了兩個以上的字符串,所以如果你一次爲所有的連接分配了內存,那將是最好的。

#include <stdarg.h> 
#include <string> 
char* stringBuilder(int count, ...) 
{ 
    va_list ap, vacnt; 
    int j; 
    int len = 1; 
    char* buffer; 
    va_start(ap, count); 
#ifdef va_copy 
     va_copy(vacnt,ap); 
#else 
    vacnt = ap; 
#endif 
    for(j=0; j<count; ++j){ 
     len+=strlen(va_arg(vacnt, char*)); 
    } 
    va_end(vacnt); 
    buffer = (char*) malloc(len * sizeof(char)); 
    buffer[0]=0; 
    for (j=0;j<count;++j) { 
     strcat (buffer, va_arg(ap, char*)); 
    } 
    va_end(ap); 
    return buffer; 
} 

你可以使用它作爲這樣的:

char* x = stringBuilder(4,"hello", " ", "world", "\n"); 
printf(x); 
free(x); 

還要注意,鍵和值必須是URL編碼爲您的應用程序的目的

+0

非常有幫助!謝謝。 – jkushner