通过分界线将getline解析为缓冲区?

时间:2018-10-18 04:06:09

标签: 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;
        }


    }

}

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

  

警告:从指针转换为不同大小的整数   [-指向指针的指针]                myargv [i] =(字符)令牌;

不确定我到底在做什么错。

谢谢!

2 个答案:

答案 0 :(得分:2)

虽然并不能100%清楚您要用代码完成的全部工作,但是使用多个指针有点尴尬。

对您来说,响起警钟的第一件事是您需要明确地转换为(char)。如果您发现自己试图进行转换以避开编译器警告或错误-停止-您做错了什么。

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

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

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

您可以随意声明NULL的分隔符,但是由于您使用strtok正确定义了常量,因此没有理由不为#define分隔符添加常量还有,例如<​​/ p>

strtok

如果您未在代码中使用#include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFFERSIZE 256 #define PROMPT "myShell >> " #define DELIM " \n" argc,则argv的正确声明为:

main()

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

如果仅读取行并标记要与int main (void) { 一起使用的行,则在循环范围内声明并初始化变量 确保它们是正确地重新初始化每次迭代,例如

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声明为nchr(POSIX ssize_t的正确返回类型),可以简化getline的测试,例如

EOF

剩下的就是标记 fputs (PROMPT, stdout); if ((nchr = getline (&line, &n, stdin)) == -1) { putchar ('\n'); /* tidy up with newline */ break; } 并在适当的索引(line)上分配指向myargv的指针。您可以使用ndx循环,但是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并将令牌复制到新的内存块。(myargv[ndx]malloc,或者strcpy(如果有))

最后,请不要忘记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;
}

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

答案 1 :(得分:0)

来自strtok

  

char * strtok(char * str,const char * delim);

在您的作业中,返回类型为char *

myargv[i] = (char) tokens;

您正在做typecastchar *的{​​{1}},我确定这不是您想做的事

可能与此有关

更改char以容纳令牌数组

myargv

,并在char myargv[MAX_TOKENS][BUFFERSIZE]; 循环而不是分配while中使用myargv[i] = (char) tokens

strcpy

让我尝试解释为什么您的原始程序行为异常

        strcpy(myargv[i], tokens);
        printf("%s\n", myargv[i]);

在这里char myargv[BUFFERSIZE]; 被分配了一个myargv vitz 256的内存,如

BUFFERSIZE

每个块的大小为+---+---+---+---+---+---+---+---+....---+---+ | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+ 0 1 2 .. 255 sizeof(char)

1 byte循环此处

while

您有一个myargv[i] = (char) tokens; ,本质上是一个char *数字,如果您真的去那个地址并查看那里的内容4 byte,则应该已经看到第一个令牌。但是,您现在正尝试将byte by byte放入4 byte address中,导致截断和赋值。

然后是1 byte indexed location

printf

根据上一步的操作,printf("%c\n", myargv[i]); 现在包含一个地址的剥离版本,该地址只是一个数字myargv[i]格式说明符尝试将其转换为相应的{{1 }},并打印出垃圾内容。

我建议您阅读"%c\n"ascii2d-arrays

上的内容。