C - 打印到文件会导致乱码,但打印到stdout不会?

时间:2018-03-04 14:13:16

标签: c recursion file-io printf binary-search-tree

我几小时前制作了这个帖子:

Tricky Segmentation faults with BST recursion in C

经过几个小时的尝试后管理好了。然而,我遇到了另一个问题。这是一个奇怪的。透视的相关代码:

extern char *optarg;
extern int optind;
int c, err = 0;
char currentLine[STRING_SIZE];
char fileDirectory[STRING_SIZE];

static char usage[] = "Usage: %s [-c] [-o output_file_name] [input_file_name]\n";

while ((c = getopt(argc, argv, "co:")) != -1)
    switch (c)
    {
        case 'c':
            cflag = 1;
            break;
        case 'o':
            oflag = 1;

            // If an output file name
            // was entered, copy it
            // to fileDirectory

            if (optarg != NULL)
            {
                strcpy(fileDirectory, optarg);
            }

            break;
        default:
            err = 1;
            break;
    }

if (err)
{
    fprintf(stderr, usage, argv[0]);
    exit(1);
}

// --- BST SORT CODE STARTS HERE ---

// This is the BST. As the assignment instructions
// specify, it is initially set to NULL

BST *root = NULL;

// Pointer to the mode the files
// will be opened in. Starts as
// "w" since we're opening the output file
// first

char *mode = (char*)malloc(sizeof(char*));
strcpy(mode, "w");

FILE *outFile;
outFile = fopen(fileDirectory, mode);

// Now update mode and fileDirectory so
// we can open the INPUT file
strcpy(mode, "r");

// Check if we have an input file name
// If argv[optind] isn't NULL, that means we have
// an input file name, so copy it into fileDirectory

if (argv[optind] != NULL)
{
    strcpy(fileDirectory, argv[optind]);
}
FILE *inFile;

// Attempt to open the input file
//inFile = fopen(fileDirectory, mode);
fopen(fileDirectory, mode);

    if (inFile != NULL)
{
    // Process the file while EOF isn't
    // returned
    while (!feof(inFile))
    {
        // Get a single line (one string)
        fgets(currentLine, STRING_SIZE, inFile);

        // Check whether the line is an empty line
        if (*currentLine != '\n')
        {
            // If the string isn't an empty line, call
            // the insert function
            root = insert(root, currentLine);
        }
    }
    // At this point, we're done processing
    // the input file, so close it
    fclose(inFile);
}

// Otherwise, process user input from standard input
else
{
    do
    {
        printf("Please enter a string (or blank line to exit): ");

        // Get a single line of input from the user
        fgets(currentLine, STRING_SIZE, stdin);

        // If this is our first call to the
        // insert function, set root to point
        // to the branch created (which is
        // the actual "root" of the tree)
        if (root == NULL)
        {
            root = insert(root, currentLine);
        }
        // Otherwise, simply call the insert
        // function on the root of the tree
        else
        {
            insert(root, currentLine);
        }
    } while (caseSenStrCmp(currentLine, "\n") != 0);

}

// At this point, we've read all the input, so
// perform in-order traversal and print all the
// strings as per assignment specification

inOrderPrint(root, oflag, outFile);

// We're done, so reclaim the tree
deallocateTree(root);

// Finally, if we have an outFile, close it
if (outFile)
{
    fclose(outFile);
}

}

以上是我的主文件的摘录(如果你很好奇,你可以在我的另一个帖子中看到整个内容)。对inFile的分配被注释掉了,因为我也遇到了麻烦 - 只是忽略它(我不认为它与这个问题有任何关系)

以下是执行二进制搜索树的有序遍历并将存储在其分支中的字符串打印到stdout(如果oflag未设置或没有输出文件)或输出文件(如果设置了标志并且输出文件存在):

void inOrderPrint(BST *root, int oflag, FILE *outFile)
{
// Check if the current branch is null

if (root == NULL)
{
    return;
}
    // Otherwise, perform the in-order traversal
else
{
    // This counter will be used in a loop
    // that will print the strings in the branches
    int count;

    if (root->left != NULL)
    {
        inOrderPrint(root->left, oflag, outFile);
    }

    // If the oflag is set and outFile
    // isn't NULL, then we can print to
    // the output file

    if (oflag && (outFile != NULL))
    {
        // Print the string as many times
        // as it occurs in the tree
        for (count = 0; count < root->counter; count++)
        {
            //fprintf(outFile, "%s\n", root->key);
            fputs(root->key, outFile);

            // !!! Does the fflush go here? !!!
            fflush(outFile);
        }
    }

        // Otherwise, print to stdout
    else
    {
        // Same idea as above: print
        // as many times as there are
        // instances of the string in the tree

        for (count = 0; count < root->counter; count++)
        {
            printf("%s\n", root->key);
        }
    }

    if (root->right != NULL)
    {
        inOrderPrint(root->right, oflag, outFile);
    }
}
}

这次问题(实际上有两个,但我会首先处理这个问题)是当未设置oflag时(也就是说,当我没有指定输出文件时)和字符串在节点中必须打印到stdout(在这种情况下是控制台),这通过这段代码发生:

else
    {
        // Same idea as above: print
        // as many times as there are
        // instances of the string in the tree
        for (count = 0; count < root->counter; count++)
        {
            printf("%s\n", root->key);
        }
    }

它的工作非常精美 - 字符串打印完美,就像它们应该的那样。但是,当我尝试打印到输出文件时,基于块发生:

if (oflag && (outFile != NULL))
        {
            // Print the string as many times
            // as it occurs in the tree
            for (count = 0; count < root->counter; count++)
            {
                //fprintf(outFile, "%s\n", root->key);
                fputs(root->key, outFile);
            }
        }

它打印垃圾(忽略已注释掉的fprintf语句;这只是我试图看看是否使用fputs会产生影响 - 它没有)。请注意,不是很多。

只是一个符号,即这一个:ø

有趣的是,输出文件的大小会以与“写入”文件的字符串数量一致的方式改变 - 树中必须写入的字符串越多,大小越大(如,它占用的内存量)输出文件。然而,无论文件有多大,实际上写在文件上的只是一个ø

我不明白为什么会这样,或者如何解决它。使用root-&gt;键打印到控制台的工作完美地告诉我,这可能不是因为写入的字符串是NULL或无效。

我唯一的猜测是它与我将指针传递给字符串的方式有关(即root-&gt; key vs *(root-&gt; key))?

createBranch()和insert()函数创建新节点并将它们插入BST,以供参考

BST* createBranch(char *keyVal)
{
// Create the new branch
BST* newBranch = (BST*)malloc(sizeof(BST));

// Allocate memory for newBranch's C-string
newBranch->key = (char*)malloc(STRING_SIZE * sizeof(char));

// Copy the user-provided string into newBranch's
// key field
strcpy(newBranch->key, keyVal);

// Set newBranch's counter value to 1. This
// will be incremented if/when other instances
// of the key are inserted into the tree

newBranch->counter = 1;

newBranch->left = NULL;
newBranch->right = NULL;

return newBranch;
}


// Adds items to the BST. Includes functionality
// to verify whether an item already exists in the tree

BST* insert(BST* root, char *key)
{

// If branch is null, call createBranch
// to make one, then return it

if (root == NULL)
{
    return createBranch(key);
}

// Otherwise, check whether the key
// already exists in the tree

if (!existsInTree(root, key, cflag))
{
    // If it doesn't, check whether
    // the case sensitivity flag is set
    if (cflag)
    {
        // If it is, use the case-sensitive
        // string comparison function

        if (caseSenStrCmp(root->key, key))
        {
            // If the key provided is greater
            // than the string stored at the
            // current branch, insert into
            // right child

            root->right = insert(root->right, key);
        }
        else
        {
            // Otherwise, insert into left child

            root->left = insert(root->left, key);
        }
    }
    // If it isn't, use the case-INsensitive string
    // comparison function to decide where to insert
    else
    {
        // Same logic as before
        if (caseInsenStrCmp(root->key, key))
        {
            root->right = insert(root->right, key);
        }
        else
        {
            root->left = insert(root ->left, key);
        }
    }
}

return root;
}

修改

我已经更新了第一个大代码块以包含其余主要内容 功能

@dmuir:

我在main结束时关闭outFile(检查我帖子中第一个大块代码的结尾),但我从未使用fflush甚至没有听说过它。我快速浏览了它的文档,看起来它意味着在每个打印输出文件的实例之后使用,所以缓冲区是否清晰,以便打印下一个值?

我在printInOrder()函数中包含了它的测试用法(这篇文章的第二大代码块,两侧是!!!)。不幸的是,使用此添加的代码的测试运行并没有解决问题,但我甚至不确定我是否正确使用它?

@Iharob Al Asimi

道歉有关多余的空白。我主要是在我仍然把程序放在一起的时候这样做 - 一旦一切正常,我通常会回过头来大幅减少评论和空格,这样它看起来就像现在一样。

至于我如何将值插入树中,我已将我的createBranch()和insert()函数添加到帖子(粗体“EDIT”上方的大块代码)。

我不太确定我是如何插入值或者它们不是NULL字符终止的问题,因为正如我所说,将值打印到CONSOLE工作得很好。只有当我尝试打印到FILE时才能获得单个垃圾字符ø

@William Pursell:

对错误陈述道歉。那是作为测试而放在那里的 我正在编写getopt代码,我只是忘了擦掉它。我暂时删除它,因为它与我遇到的问题无关(我认为)。

0 个答案:

没有答案