关于io:在C中从STDIN解析后输出的垃圾字符

Junk Characters Outputted After Parsing From STDIN in C

在阅读的某些文本的末尾,我将输出一个垃圾字符:

1
2
3
4
5
hum 1345342342 ~Users/Documents ecabd459 //line that was read in from stdin
event action: hum_?
event timestamp: 1345342342
event path: ~Users/Documents
event hash: ecabd459

事件操作值的末尾有一个'_?'以及输出的垃圾字符。可以通过将变量的最后位置设置为空终止符(event.action[3] = '\\0')来纠正这一问题,该终止符很好,但我为另一个char数组event.hash没有表现出这种类型的事实感到困惑。我以相同的方式创建/打印它们,但是散列的行为并不相同。

注意:我正在考虑,可能是由于哈希值严格后跟换行符(顺便说一句,我将其除去了),所以我对程序进行了重新排序,但无济于事(即,在行上哈希值的位置之后添加了一个额外的空格和单词。)

相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
struct Event{
    char action[4];
    long timest
    char* path;
    char hash[9];
};  

// parse line and return an Event struct
struct Event parseLineIntoEvent(char* line) {
    struct Event event;
    char* lineSegment;

    int i = 0;
    lineSegment = strtok(line,"");
    while (lineSegment != NULL) {
        if (i > 3) {
            printf("WARNING: input format error!\
"
);
            break;
        }
        if (i == 0)
            strncpy(event.action, lineSegment, sizeof(event.action)-1);
        else if(i == 1)
            event.timestamp = atoi(lineSegment);
        else if(i == 2) {
            event.path = malloc(sizeof(lineSegment));
            strcpy(event.path, lineSegment);
        } else if(i == 3)
            strncpy(event.hash, lineSegment, sizeof(event.hash)-1);
        lineSegment = strtok(NULL,"");
        i++;
    } // while
    return event;
} // parseLineIntoEvent()

int main (int argc, const char * argv[]) {
//...
    printf("%s\
"
,line); //prints original line that was read in from stdin
    struct Event event = parseLineIntoEvent(line);
    printf("event action: %s\
"
, event.action);
    printf("event timestamp: %lu\
"
, event.timestamp);
    printf("event path: %s\
"
, event.path);
    printf("event hash: %s\
"
, event.hash);
    free(event.path);
    free(line);
//...
    return 0;
}

编辑:
我用此功能读了一行,它摆脱了换行符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// read in line from stdin, eliminating newline character if present
char* getLineFromStdin() {
    char *text;
    int textSize = 50*sizeof(char);
    text = malloc(textSize);

    if ( fgets(text, textSize, stdin) != NULL ) {
        char *newline = strchr(text, '\
'
); // search for newline character
        if ( newline != NULL ) {
            *newline = '\\0'; // overwrite trailing newline
        }
    }
    return text;
}

预先感谢!


这是一个错误:

1
event.path = malloc(sizeof(lineSegment));

当需要长度加一个终止NULL字符时,

将返回sizeof(char*)

1
event.path = malloc(sizeof(char) * (strlen(lineSegment) + 1));

为避免必须在actionhash中插入空字符串终止符,可以初始化event

1
struct Event event = { 0 };


在Linux手册页中:

1
2
3
The strncpy() function is similar, except that at most n bytes of src are copied.
Warning: If there is no null byte among the first n bytes of src, the string
placed in dest will not be null-terminated.

执行strncpy时,必须确保目标字符串正确终止。

更改event.action字段的设置:

1
2
3
4
5
if (i == 0)
{
    strncpy(event.action, lineSegment, sizeof(event.action)-1);
    event.action[sizeof(event.action)-1] = '\\0';
}


but I am perplexed by the fact that the other char array event.hash does not exhibit this type of behavior

你真倒霉。由于运气不好,hash [8]可能已获得" \\\\ 0"。

在您的strtok循环之前尝试将其设置为"随机"

1
2
3
4
    int i = 0;
    event.hash[8] = '_';             /* forcing good-luck */
    lineSegment = strtok(line,"");
    while (lineSegment != NULL) {


这是因为字符串" num"仅包含4个元素字符数组Event.action中的三个元素,而第四个元素将保持不变。因为没有为Event.action数组元素设置任何内容,所以它将指向随机存储器位置,该位置存储了一些随机值。当您打印此字符数组时,它将打印所有元素,而不是指向有效数据的那些元素。这将导致显示垃圾字符。