我在代碼中的目標是將某種輸入決議為有關所有空格的單詞,但同時使用這些空格來表示單詞的變化。這里的邏輯是,只要遇到空格,它就會回圈直到不再有空格字符,然后當它遇到一個單詞時,它回圈直到遇到空格字符或'\0',同時將每個字符放入一個索引二維陣列中的陣列內的陣列。然后在 while 回圈再次繼續之前,它索引到下一個陣列。
我幾乎可以肯定邏輯實作得足夠好,可以正常作業,但我得到了下面列出的這個奇怪的輸出我之前在處理指標和諸如此類的東西時遇到過同樣的問題,但無論如何我都無法讓它作業我愿意。關于為什么我真的對背后的原因感到好奇的任何想法?
#include <stdio.h>
#include <stdlib.h>
void print_mat(char **arry, int y, int x){
for(int i=0;i<y;i ){
for(int j=0;j<x;j ){
printf("%c",arry[i][j]);
}
printf("\n");
}
}
char **parse(char *str)
{
char **parsed=(char**)malloc(sizeof(10*sizeof(char*)));
for(int i=0;i<10;i ){
parsed[i]=(char*)malloc(200*sizeof(char));
}
char **pointer = parsed;
while(*str!='\0'){
if(*str==32)
{
while(*str==32 && *str!='\0'){
str ;
}
}
while(*str!=32 && *str!='\0'){
(*pointer) = (str);
(*pointer) ;
str ;
}
pointer ;
}
return parsed;
}
int main(){
char str[] = "command -par1 -par2 thething";
char**point=parse(str);
print_mat(point,10,200);
return 0;
}
-par1 -par2 thethingUP%?W???U?6o? X%??U?v;,???UP%???cNjW??]A?aW??to?8so?z?
-par2 thethingUP%?W???U?6o? X%??U?v;,???UP%???cNjW??]A?aW??to?8so?z?
thethingUP%?W???U?6o? X%??U?v;,???UP%???cNjW??]A?aW??to?8so?z?
UP%?W???U?6o? X%??U?v;,???UP%???cNjW??]A?aW??to?8so?z?
我也嘗試簡單地索引二維陣列但無濟于事
char **parse(char *str)
{
int i, j;
i=0;
j=0;
char **parsed=(char**)malloc(sizeof(10*sizeof(char*)));
for(int i=0;i<10;i ){
parsed[i]=(char*)malloc(200*sizeof(char));
}
while(*str!='\0'){
i=0;
if(*str==32)
{
while(*str==32 && *str!='\0'){
str ;
}
}
while(*str!=32 && *str!='\0'){
parsed[j][i] = (*str);
i ;
str ;
}
j ;
}
return parsed;
}
輸出:
command?&?v?U`'?v?U0(?v?U)?v?U?)?v?U
-par1
-par2
thething
makefile:5: recipe for target 'build' failed
make: *** [build] Segmentation fault (core dumped)
uj5u.com熱心網友回復:
您的代碼中有幾個問題:
- 您的程式正在泄漏記憶體。
- 您的程式正在訪問它不擁有的記憶體,這是 UB。
讓我們一一討論——
第一個問題 - 記憶體泄漏:
檢查這部分parse()功能:
while(*str!=32 && *str!='\0'){
(*pointer) = (str);
在外while回圈的第一次迭代中,*pointer將為您提供陣列的第一個成員parsedie parsed[0],它是指向 的指標char。請注意,您在外回圈之前將記憶體動態分配給parsed[0], parsed[1]...parsed[9]指標。在內部回圈中,您將它們指向. 因此,它們將丟失動態分配的記憶體參考并導致記憶體泄漏。parse()whilewhilestr
第二個問題 - 訪問它不擁有的記憶體:
如上所述,指標parsed[0]等parsed[1]將指向函式str內部while回圈中的當前值parse()。這意味著,指標parsed[0]等parsed[1]將指向陣列的某個元素str(在 中定義main())。在print_mat()函式中,您將200陣列的每個指標從arry索引傳遞和訪問。由于指標指向大小為 的陣列,這意味著您的程式正在訪問超出其大小(UB)的記憶體(陣列)。0199arrystr29
讓我們在您的代碼中解決這些問題,而無需進行太多更改:
對于記憶體泄漏:
不要將指標指向 ,而是str將字符str分配給分配的記憶體,如下所示:
int i = 0;
while(*str!=32 && *str!='\0'){
(*pointer)[i ] = (*str);
str ;
}
訪問它不擁有的記憶體:
您應該記住的一點:
在 C 中,字串實際上是由空字符終止的一維字符陣列\0。
首先,在動態分配記憶體后清空字串,以便在列印時識別未使用的指標:
for(int i=0;i<10;i ){
parsed[i]=(char*)malloc(200*sizeof(char));
parsed[i][0] = '\0';
}
將單詞寫入parsed陣列指標后,用空終止符終止所有字串:
int i = 0;
while(*str!=32 && *str!='\0'){
(*pointer)[i ] = (*str);
str ;
}
// Add null terminator
(*pointer)[i] = '\0';
在 中print_mat(),請確保一旦您點擊了空終止符,就不要閱讀它。修改內for回圈條件:
for(int j = 0; (j < x) && (arry[i][j] != '\0'); j ){
printf("%c",arry[i][j]);
您不需要逐個字符地列印字串,您可以簡單地使用%s格式說明符來列印字串,如下所示 -
for (int i = 0;i < y; i ) {
if (arry[i][0] != '\0') {
printf ("%s\n", arry[i]);
}
}
通過上述建議的更改(這是程式正常作業所需的最小更改),您的代碼將如下所示:
#include <stdio.h>
#include <stdlib.h>
void print_mat (char **arry, int y) {
for (int i = 0; i < y; i ) {
if (arry[i][0] != '\0') {
printf ("%s\n", arry[i]);
}
}
}
char **parse(char *str) {
char **parsed = (char**)malloc(sizeof(10*sizeof(char*)));
// check malloc return
for(int i = 0; i < 10; i ){
parsed[i] = (char*)malloc(200*sizeof(char));
// check malloc return
parsed[i][0] = '\0';
}
char **pointer = parsed;
while (*str != '\0') {
if(*str == 32) {
while(*str==32 && *str!='\0') {
str ;
}
}
int i = 0;
while (*str != 32 && *str != '\0') {
(*pointer)[i ] = (*str);
str ;
}
(*pointer)[i] = '\0';
pointer ;
}
return parsed;
}
int main (void) {
char str[] = "command -par1 -par2 thething";
char **point = parse(str);
print_mat (point, 10);
// free the dynamically allocate memory
return 0;
}
輸出:
command
-par1
-par2
thething
在您的代碼實作中可以做很多改進,例如 -
- 正如我上面所展示的,您可以使用
%s格式說明符而不是逐個字符地列印字串等。我將由您來確定這些更改并修改您的程式。 - 僅
parsed在str. - 與其將固定大小的記憶體(即
200)分配給parsed陣列指標,不如只分配字大小的記憶體。
幾點建議:
- 始終檢查函式的回傳值,例如
malloc. - 確保在程式完成后釋放動態分配的記憶體。
uj5u.com熱心網友回復:
你可以用更簡單的方式實作你想要的。
首先,定義一個函式來檢查字符(分隔符)是否存在于字串列(分隔符)中:
// Returns true if c is found in a list of separators, false otherwise.
bool belongs(const char c, const char *list)
{
for (const char *p = list; *p; p)
if (*p == c) return true;
return false;
}
然后,定義一個將給定字串拆分為標記的函式,由一個或多個分隔符分隔:
// Splits a string into into tokens, separated by one of the separators in sep
bool split(const char *s, const char *sep, char **tokens, size_t *ntokens, const size_t maxtokens)
{
// Start with zero tokens.
*ntokens = 0;
const char *start = s, *end = s;
for (const char *p = s; /*no condtition*/; p) {
// Can no longer hold more tokens? Exit.
if (*ntokens == maxtokens)
return false;
// Not a token? Continue looping.
if (*p && !belongs(*p, sep))
continue;
// Found a token: calculate its length.
size_t tlength = p - start;
// Empty token?
if (tlength == 0) {
// And reached the end of string? Break.
if (!*p) break;
// Not the end of string? Skip it.
start;
continue;
}
// Attempt to allocate memory.
char *token = malloc(sizeof(*token) * (tlength 1));
// Failed? Exit.
if (!token)
return false;
// Copy the token.
strncpy(token, start, tlength 1);
token[tlength] = '\0';
// Put it in tokens array.
tokens[*ntokens] = token;
// Update the number of tokens.
*ntokens = 1;
// Reached the end of string? Break.
if (!*p) break;
// There is more to parse. Set the start to the next char.
start = p 1;
}
return true;
}
像這樣稱呼它:
int main(void)
{
char command[] = "command -par1 -par2 thing";
const size_t maxtokens = 10;
char **tokens = malloc(sizeof *tokens * maxtokens);
if (!tokens) return 1;
size_t ntokens = 0;
split(command, " ", tokens, &ntokens, maxtokens);
// Print all tokens.
printf("Number of tokens = %ld\n", ntokens);
for (size_t i = 0; i < ntokens; i)
printf("%s\n", tokens[i]);
// Release memory when done.
for (size_t i = 0; i < ntokens; i)
free(tokens[i]);
free(tokens);
}
輸出:
Number of tokens = 4
command
-par1
-par2
thing
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/450301.html
