簡體   English   中英

使用 strtok_r 時指針無效

[英]invalid pointer when using strtok_r

運行我的代碼時(顯示在第一個代碼塊中),我收到此錯誤: *** Error in `./a.out': free(): invalid pointer: 0x0000000001e4c016 ***我找到了一個修復程序(如圖所示在第二個代碼塊中),但我不明白為什么首先會發生錯誤。

我閱讀了有關 strtok_r 的文檔,但我不明白為什么將“str”分配給新的 char* 可以解決問題。

“rest = str”是否意味着 rest 和 str 指向 memory 的同一塊。 這如何解決問題???

損壞的代碼:

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

int main() 
{ 
    char* str = (char*) malloc(sizeof(char) * 128);
    char* token;
    
    printf("Enter something: ");  
    fgets(str, 128, stdin);
  
    while ((token = strtok_r(str, " ", &str))) { 
        printf("%s\n", token); 
    }
    
    free(str);
    return (0); 
}

固定代碼:

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

int main() 
{ 
    char* str = (char*) malloc(sizeof(char) * 128);
    char* token; 
    char* rest = str; 
    
    printf("Enter something: ");  
    fgets(str, 128, stdin);
  
    while ((token = strtok_r(rest, " ", &rest))) { 
        printf("%s\n", token); 
    }
    
    free(str);
    return (0); 
}

顯然,對strtok_r的調用更改了指針str ,該指針作為第三個參數通過引用傳遞給調用。

while ((token = strtok_r(str, " ", &str))) { 
                                   ^^^^
    printf("%s\n", token); 
}

因此,在調用 function 之后,指針str可以指向原始字符串內部。 所以它不會存儲它在調用malloc之后的值。

因此,使用輔助變量 rest 允許將初始值保留在指針str中。

請注意,您錯誤地調用了 function。 這是它的描述

在第一次調用strtok_r()時, str應該指向要解析的字符串,並且忽略saveptr的值。 在隨后的調用中, str應該是NULL ,並且saveptr應該自上次調用以來保持不變。

因此,對於 function 的第二次和后續調用,第一個參數應為NULL

你應該寫:

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

int main() 
{ 
    char  str[128];
    char *token; 
    char *rest = str; 
    
    printf("Enter something: ");  
    fgets(str, sizeof str, stdin);
  
    for (token = strtok_r(rest, " ", &rest);
         token = strtok_r(NULL, " ", &rest);
         /* just nothing here */)
    { 
        printf("%s\n", token); 
    }
    
    return (0); 
}
  • 首先,您不需要為str分配 memory ,因為您可以定義一個本地數組來存儲數據。 您可以使用sizeof運算符,這樣如果您決定更改str的大小,就不會冒在兩個地方不更新它的風險。 在使用malloc的情況下,您最好#define一個常量來保存該值,同時在使用分配緩沖區大小的任何地方使用該常量。
  • 其次,永遠不要malloc的返回值。 相信我,這是一個非常壞的習慣。 當你進行強制轉換時,你告訴編譯器你知道你在做什么。 鑄造 malloc 的值是malloc中沒有void類型時的遺留物(直到八十年代中期)。 曾幾何時, malloc()用於返回一個char * ,這通常不是您想要的指針類型,您必須強制轉換指針以匹配您正在使用的指針。 不僅不建議在 2021 年強制轉換malloc()返回值,而且強烈建議不要這樣做,因為許多錯誤來自於強制轉換(編譯器會在您做錯事時警告您,但如果您強制轉換該值,則不會,通常這被解釋為你告訴編譯器你故意在做一些奇怪的事情,所以編譯器關閉,不再多說)
  • 第三,如果要提取字符串中的所有標記,第一次調用strtok() (或他的朋友strtok_w )時,第一個參數指向字符串的開頭,但調用的 rest 有以NULL作為第一個參數來完成,否則您將在剛剛返回的字符串中進行搜索,而不是在第一次出現的后面。 您的問題與使用strtokstrtok_r ,因為strtok_r只是strtok的可重入版本,它允許您在第一個循環內啟動嵌套循環,或從不同的線程調用它。

堆 memory 管理跟蹤基本 memory 地址以實現庫調用。 我們需要保留這些基地址,以便在必要時釋放/重新分配。

既然您找到了使用strtok_r()的方法,我更喜歡以下版本:

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

int main () {
    char orgStr [] = "strtok does not allow you to have 2 pointers going at once on the same string";

    for (char *token, *rmdStr = orgStr; token = strtok_r (NULL, " ", &rmdStr); /* empty */) {
        printf ("%s\n", token);
    }
    /* Original string is chopped up with NULCHAR, now unreliable */
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM