2017-11-29 8 views
0

私はカンマで区切られた行をトークン化しています。いくつかのタイトルにはコンマが入っているので引用符で囲まれています。私は最初の見積もりまでトークン化し、それをフロントトークンに格納し、次に2番目の見積もりに格納し、タイトルに格納してから、最後に\ nまでトークン化します。なぜか分からない。同じ文字列で2回目のstrcpyを実行すると奇妙なセグメンテーションフォールトC

strsepと関連がありますか?文字列が ",,"の間に何もない複数の区切り文字で構成されている場合、nullトークンをキャッチしたいので、私はstrtokを使用しませんでした。

tempStrは必要な量を十分に上回っているので、strcpyの* destとして十分でなければなりません。私はこれに何時間も執着している。誰かが私の間違いを指摘できれば、私はそれを高く評価します。ありがとうございました。

int main(int argc, char * argv[]) 
{ 
    char* one = "hello, my, name, is, code monkey, \"This, is a title\", more, random, stuff\n"; 
    char* two = "blah blah blah"; 

    char* tempStr= malloc(1000); 
    void* freeTempStr = tempStr; 

    strcpy(tempStr, one); 

    char* fronttoken = strsep(&tempStr, "\""); 
    char* title = strsep(&tempStr, "\""); 
    char* backtoken = strsep(&tempStr, "\n"); 
    char* token; 

    strcpy(tempStr, fronttoken); 
    token = strsep(&tempStr, ","); 
    while (token != NULL) 
    { 
     printf("Front tokens: %s\n", token); 
     token = strsep(&tempStr, ","); 
    } 
    printf("Title: %s\n", title); 
    strcpy(tempStr, backtoken); 
    token = strsep(&tempStr, ","); 
    while (token != NULL) 
    { 
     printf("Back tokens: %s\n", token); 
     token = strsep(&tempStr, ","); 
    } 
    //2nd strcpy gives segmentation fault 

    free(freeTempStr) 
    return 0; 
} 

出力...

Front tokens: hello 
Front tokens: my 
Front tokens: name 
Front tokens: is 
Front tokens: code monkey 
Front tokens: 
Title: This, is a title 
Segmentation fault 
+1

あなたは何をしようとしているのか分かりません。本当に 'strsep()'の動​​作を理解していますか? – Stargateur

+1

セパレータが見つからない場合、 'strsep'は' tempStr'を 'NULL'に設定します。したがって、おそらく' strcpy'の最初の引数としてNULLを渡してsegfaultを引き起こします。この仮説をテストするには、デバッガを使用し、segfaultが起きたときに 'tempStr'の値を調べてください。 –

+0

@Stargateurムービー属性を含む大きなCSVファイルを正しくトークン化しようとしています。映画の中にはタイトルのカンマがあるものがあります。そのため、タイトルのカンマを囲むために前後のトークンがあります。 – codemonkey

答えて

0

は、コードを困難に見て、コンパイルし、それを試した、私は「当面の問題はあなたのことであるとのanalysisM.Mに同意します再 ヌルポインタにコピーしようとしています。

しかし、あなたは一般的にメモリ管理を慎重に検討していないと思われます。 strcpy(tempStr, one);を実行すると、ソース文字列が割り当てられたメモリにコピーされます。 (Un)幸いにも、あなたは必要なコピーよりもはるかに多くのメモリを割り当てました。続いてstrcpy(tempStr, fronttoken);を実行するときは、元のコピーoneの後にfronttokentempStrにコピーします。その後、それを分割します。

tempStrがヌルに設定されていて、ヌルポインタにコピーすると、strcpy(tempStr, backtoken)が試行されたため、クラッシュする可能性があります。

これを修正すると、重複する文字列のコピーの問題に遭遇する可能性があります。現在のバックトークンのセットは十分に小さいので問題はありませんが、100バイトのバックトークンがあれば、重複するストリングコピーと未定義の動作が発生します。

このコードは、問題を示して修正します。トークンの周囲に角括弧が含まれているため、見つかったものを正確に見るのが簡単です。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) 
{ 
    char* one = "hello, my, name, is, code monkey, \"This, is a title\", more, random, stuff\n"; 

    char* tempStr= malloc(1000); 
    void* freeTempStr = tempStr; 

    strcpy(tempStr, one); 
    printf("tempStr = [%p .. %p)\n", (void *)tempStr, (void *)(tempStr + 1000)); 

    char* fronttoken = strsep(&tempStr, "\""); 
    printf("tempStr = %p; fronttoken = %p\n", (void *)tempStr, (void *)fronttoken); 
    char* title = strsep(&tempStr, "\""); 
    printf("tempStr = %p; title = %p\n", (void *)tempStr, (void *)title); 
    char* backtoken = strsep(&tempStr, "\n"); 
    printf("tempStr = %p; backtoken = %p\n", (void *)tempStr, (void *)backtoken); 
    char* token; 

    printf("tempStr = %p; fronttoken = %p - before strcpy 1\n", (void *)tempStr, (void *)fronttoken); 
    strcpy(tempStr, fronttoken); 
    token = strsep(&tempStr, ","); 
    while (token != NULL) 
    { 
     printf("Front tokens: %p [%s]\n", (void *)token, token); 
     token = strsep(&tempStr, ","); 
    } 
    printf("Title: [%s]\n", title); 
    printf("tempStr = %p; backtoken = %p - before strcpy 2 (unfixed)\n", tempStr, backtoken); 
    tempStr = freeTempStr; 
    printf("tempStr = %p; backtoken = %p - before strcpy 2 (fixed - but beware overlap)\n", tempStr, backtoken); 
    strcpy(tempStr, backtoken); 
    token = strsep(&tempStr, ","); 
    while (token != NULL) 
    { 
     printf("Back tokens: %p [%s]\n", (void *)token, token); 
     token = strsep(&tempStr, ","); 
    } 

    free(freeTempStr); 
    return 0; 
} 

出力例(Macがインストールされているセキュリティ更新2017から001に、MacOSのハイシエラ10.13.1を実行している - macOS 10.13.1 (17B1002) - あなたはまだ行っていないしている場合はそれをインストール!):

tempStr = [0x7fb91ac02880 .. 0x7fb91ac02c68) 
tempStr = 0x7fb91ac028a3; fronttoken = 0x7fb91ac02880 
tempStr = 0x7fb91ac028b4; title = 0x7fb91ac028a3 
tempStr = 0x7fb91ac028ca; backtoken = 0x7fb91ac028b4 
tempStr = 0x7fb91ac028ca; fronttoken = 0x7fb91ac02880 - before strcpy 1 
Front tokens: 0x7fb91ac028ca [hello] 
Front tokens: 0x7fb91ac028d0 [ my] 
Front tokens: 0x7fb91ac028d4 [ name] 
Front tokens: 0x7fb91ac028da [ is] 
Front tokens: 0x7fb91ac028de [ code monkey] 
Front tokens: 0x7fb91ac028eb [ ] 
Title: [This, is a title] 
tempStr = 0x0; backtoken = 0x7fb91ac028b4 - before strcpy 2 (unfixed) 
tempStr = 0x7fb91ac02880; backtoken = 0x7fb91ac028b4 - before strcpy 2 (fixed - but beware overlap) 
Back tokens: 0x7fb91ac02880 [] 
Back tokens: 0x7fb91ac02881 [ more] 
Back tokens: 0x7fb91ac02887 [ random] 
Back tokens: 0x7fb91ac0288f [ stuff] 

デバッガを使用すると、この問題をかなり早く見つけることができます。

0

あなたのコードは投稿時にコンパイルされません。セミコロンがありません。さらに、多くの標準ヘッダーがありません。

gcc 6.2.6の64ビットUbuntu 16では、あなたが見ている場所以外でクラッシュが発生します。 <string.h>ヘッダーがないため、strsep関数は暗黙のうちに返されます。intが間違っています。このため、変数fronttokenはガーベッジ値を受け取り、最初はstrcpyが失敗します。

最初に行うことは、エラーや警告なしで(コンパイラのユーザーのコミュニティが広く推奨する診断プログラムを有効にした後で)クリーンビルドを行うことです。 whileループは何のbreak文が含まれていません

while (token is not null) { 
    token = strsep(&tempStr, ...) 

} 

strcpy into tempStr 

のでtokenがnullになった場合、それが終了する唯一の方法は次のとおりです。すべてのその後

はあなたが単純な論理の問題を抱えている固定されています。

tokenが唯一の方法は、strsepがnullを返す場合です。

唯一の方法strsepは、ドキュメントに従って、tempStrがnullの場合です。

I.e. tokenがヌルであるという事実は、tempStrがヌルでなければならないことを証明します。つまり、strcpyの宛先としてtempStrを使用してはいけません。

tempStrがnullになる方法は、以前のstrsepの呼び出しでは、トークン区切り文字が見つかりませんでした。その場合、strsepは抽出されたトークンとして文字列全体を返し、ポインタをヌルで上書きします。

つまり、最後のトークンを文字列から抽出した後、strsepは、ポインタをヌルで上書きします。次に、strsepが呼び出されると、それは "それ以上のトークンが利用可能でない"ことを示すヌルを返します。これにより、strsepが使いやすいようになります。ヌルになるまで呼び出すだけです。しかし、一時的なコンテキストポインターが処理中にゼロになることを理解する必要があります。

関連する問題