C 在使用 strtok 后重新初始化变量

问题描述 投票:0回答:1

我正在尝试编写一个函数来在 PATH 目录中搜索。我使用

getenv("PATH")
获取路径字符串,然后使用
strtok()
分割它。

第二次调用函数时,它不会重新初始化路径字符串。它仅在路径的第一部分搜索。

我知道

strtok()
修改了以
\0
终止每个标记的原始字符串。但就我而言,我不明白为什么再次调用该函数不会创建带有正常分隔符“:”的新字符串。

这是我的代码:

bool str_in_path(char *target, char *result) {
  char *path = getenv("PATH");
  char *token;
  char tokens[10][100];
  int count = 0;
  
  token = strtok(path, ":");
  strcpy(tokens[0], token);
  count++;

  for (int i = 1; token && i < 10; i++) {
    token = strtok(NULL, delimiter);
    if (token) {
      strcpy(tokens[i], token);
      count++;
    }
  }

  for (int i = 0; i < count; i++) {
    struct dirent *entry = NULL
    DIR *dir = opendir(tokens[i]);
    if (dir == NULL) {
      fprintf(stderr, "can't open directory %s\n", tokens[i]);
      continue;
    }   
    while ((entry = readdir(dir)) != NULL) {
      if (!strcmp(target, entry->d_name)) {
        strcpy(result, tokens[i]);
        strcat(result, "/");
        strcat(result, entry->d_name);
        closedir(dir);
        return true;
      }   
    }
    closedir(dir);
  }
  return false;
}

我第一次调用该函数时,它的行为符合我的预期。第二次它只搜索路径的第一部分。尽管它调用

char *path = getenv("PATH");
来初始化路径字符串。为什么会这样以及我该如何解决它。

c string path strtok getenv
1个回答
0
投票

正如@chux的评论中提到的,

strcspn()
可以用于解析而不修改源字符串。
还要考虑将函数分解为两个函数。一个用于解析路径,另一个用于打开目录。

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

char **parse_path ( char *path, char *delimiter) {
    char **tokens = NULL;
    char **tmp = NULL;
    char *token = path;;
    char *end = path;
    size_t items = 0;
    size_t span = 0;

    while ( *token) { // not terminating zero
        end += strcspn ( token, delimiter);
        if ( end == token) {
            break;
        }
        if ( NULL == ( tmp = realloc ( tokens, sizeof *tokens * (items + 2)))) {
            fprintf ( stderr, "problem realloc tokens\n");
            break;
        }
        tokens = tmp;
        span = end - token;
        if ( NULL == ( tokens[items] = malloc ( span + 1))) {
            fprintf ( stderr, "problem malloc token[items]\n");
            break;
        }
        memmove ( tokens[items], token, span);
        tokens[items][span] = 0; // zero terminate
        // printf ( "\t%s\n", tokens[items]);
        ++items;
        tokens[items] = NULL; // sentenal NULL
        if ( *end) { // not terminating zero
            ++end; // advance past one delimiteer
        }
        token = end;
    }

    return tokens;
}

bool str_in_path_tokens ( char **tokens, char *target, char *result) {
    while ( tokens && *tokens) {
        struct dirent *entry = NULL;
        DIR *dir = opendir ( *tokens);
        if ( dir == NULL) {
            fprintf(stderr, "can't open directory %s\n", *tokens);
            continue;
        }
        while ( ( entry = readdir ( dir)) != NULL) {
            if ( ! strcmp ( target, entry->d_name)) {
                strcpy(result, *tokens);
                strcat(result, "/");
                strcat(result, entry->d_name);
                closedir(dir);
                return true;
            }
            closedir(dir);
        }
        ++tokens;
    }
    return false;
}

void show_path_tokens ( char **tokens) {
    while ( tokens && *tokens) {
        printf ( "%s\n", *tokens);
        ++tokens;
    }
}

void free_path_tokens ( char **tokens) {
    while ( tokens && *tokens) {
        free ( *tokens);
        ++tokens;
    }
}

int main ( void) {
    char *path = getenv ( "PATH");
    char **pathtokens = NULL;

    printf ( "%s\n", path);

    pathtokens = parse_path ( path, ":");
    show_path_tokens ( pathtokens);

    // call
    // str_in_path_tokens ( pathtokens, target, result);
    // as needed with various targets and results
    // no need to reparse the path

    free_path_tokens ( pathtokens);
    free ( pathtokens);
}
© www.soinside.com 2019 - 2024. All rights reserved.