c - 通过分隔符将 getline 解析为缓冲区?

标签 c getline

我有一个非常愚蠢的问题,我无法通过。

目标是接收用户给定的字符串,将其按空格拆分,然后将其放入数组中。

这是我目前的代码

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFFERSIZE 256
#define PROMPT "myShell >> "
#define PROMPTSIZE sizeof(PROMPT)

int main(int argc, char **argv) {


    //execvp() to locate executable

    char *buffer;
    size_t bufferSize = BUFFERSIZE;
    size_t inputSize;

    char *tokens;
    char myargv[BUFFERSIZE];

    buffer = (char *) malloc(bufferSize * sizeof(char));
    tokens = (char *) malloc(bufferSize * sizeof(char));


    while (1) {
        printf(PROMPT);
        inputSize = (size_t) getline(&buffer, &bufferSize, stdin);
        if (inputSize == 18446744073709551615) {
            break;
        }

        int i = 0;
        tokens = strtok(buffer, " ");
        while (tokens != NULL) {
            myargv[i] = (char) tokens;
            printf("%c\n", myargv[i]);
            tokens = strtok(NULL, " ");
            i = i + 1;
        }


    }

}

当我尝试编译它时,我收到了警告,

warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] myargv[i] = (char) tokens;

不太确定我做错了什么。

谢谢!

最佳答案

虽然不是 100% 清楚您要用您的代码完成的所有内容,但您对多个指针的使用有点笨拙。

应该为您敲响警钟的第一件事是您需要显式转换为 (char)。如果您发现自己试图强制转换以绕过编译器警告或错误——停止——你做错了什么。

如果您的目标是向 execvp(或类似的)提供最多 BUFFERSIZE 个参数,那么您只需将 myargv 声明为指向 char 的指针数组,例如

    char *myargv[BUFFERSIZE] = {NULL};  /* array of pointers - init NULL */

strtok 返回的每个指针都可以用作 execvp 的参数数组,如果您将数组初始化为所有 NULL 指针并且填充不超过 BUFFERSIZE - 1,确保始终向 execvp 提供参数数组,并在最后一个之后提供所需的标记 NULL争论。

您可以用任何您喜欢的方式为 strtok 声明分隔符,但是由于您使用 #define 正确定义了常量,因此没有理由不为您的 strtok 分隔符也是如此,例如

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

#define BUFFERSIZE 256
#define PROMPT "myShell >> "
#define DELIM " \n"

如果您没有在代码中使用 argcargv,那么 main() 的正确声明是:

int main (void) {

(参见:C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570)。另请参见:See What should main() return in C and C++?)

如果您只是读取该行并将该行标记化以与 execvp 一起使用,则在循环范围内声明和初始化您的变量确保每次迭代都正确地重新初始化它们,例如

    while (1) {
        size_t ndx = 0,             /* line index */
            n = 0;                  /* line alloc size (0, getline decides) */
        ssize_t nchr = 0;           /* return (chars read by getline) */
        char *line = NULL,          /* buffer to read each line */
            *myargv[BUFFERSIZE] = {NULL};  /* array of pointers - init NULL */

通过将你的 inputSize 声明为 ssize_t(POSIX getline 的正确返回类型) ,您可以简化对 EOF 的测试,例如

        fputs (PROMPT, stdout);
        if ((nchr = getline (&line, &n, stdin)) == -1) {
            putchar ('\n');         /* tidy up with newline */
            break;
        }

剩下的就是标记 line 并将指针分配给位于适当索引 (ndx) 的 myargv。您可以使用 while 循环,但 for 提供了一种使用 strtok 标记化的便捷方式,例如

        for (char *p = strtok (line, DELIM); p; p = strtok (NULL, DELIM)) {
            myargv[ndx] = p;    /* points within line, duplicate as req'd */
            printf ("token: %s\n", myargv[ndx++]);
            if (ndx == BUFFERSIZE - 1)  /* preserve sentinel NULL */
                break;
        }
        /* call to execvp, etc. here */

(注意:通过简单地将指向标记的指针分配给myargv[ndx]myargv[ndx]指向标记的位置line 内的字符串。您必须在 line 保留在范围内时使用指针。否则,您需要为每个标记分配内存,为新 block 分配起始地址内存到 myargv[ndx] 并将 token 复制到新的内存块。(mallocstrcpy,或 strdup 如果你有的话))

最后,不要忘记,getline 分配,所以不要忘记 free() 分配的内存,例如,

        free (line);    /* don't forget to free memory allocated by getline */
    }

总而言之,您可以使用类似以下内容来标记您的行:

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

#define BUFFERSIZE 256
#define PROMPT "myShell >> "
#define DELIM " \n"

int main (void) {

    while (1) {
        size_t ndx = 0,             /* line index */
            n = 0;                  /* line alloc size (0, getline decides) */
        ssize_t nchr = 0;           /* return (chars read by getline) */
        char *line = NULL,          /* buffer to read each line */
            *myargv[BUFFERSIZE] = {NULL};  /* array of pointers - init NULL */

        fputs (PROMPT, stdout);
        if ((nchr = getline (&line, &n, stdin)) == -1) {
            putchar ('\n');         /* tidy up with newline */
            break;
        }
        for (char *p = strtok (line, DELIM); p; p = strtok (NULL, DELIM)) {
            myargv[ndx] = p;    /* points within line, duplicate as req'd */
            printf ("token: %s\n", myargv[ndx++]);
            if (ndx == BUFFERSIZE - 1)  /* preserve sentinel NULL */
                break;
        }
        /* call to execvp, etc. here */

        free (line);    /* don't forget to free memory allocated by getline */
    }

    return 0;
}

示例使用/输出

$ ./bin/getlinestrtok
myShell >> my dog has fleas
token: my
token: dog
token: has
token: fleas
myShell >> my cat has none
token: my
token: cat
token: has
token: none
myShell >> happy cat
token: happy
token: cat
myShell >>

检查一下,如果您还有其他问题,请告诉我。

关于c - 通过分隔符将 getline 解析为缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52866872/

相关文章:

C Tokenizer - 它是如何工作的?

c++ - 转义(\)字符背后的魔法是什么

C:指向函数中结构体数组的指针

C++ 读/写文本文件问题

c - 在 C 中使用 fopen() 指定文件名时,/、//、\、\\有何意义?

c++ - 为什么编译器默认不自动添加或生成包含保护?

c++ - getline 删除第一个字符;删除 cin.ignore();没有解决

c++ - 不会等待 getline C++

AWK - 使用 getline 将变量传输到系统 ()?

c++ - 使用 std::getline() 读取一行?