Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
163 views
in Technique[技术] by (71.8m points)

c - Strncat causes exception

I am making a program in c to read a file and execute different pieces of code depending on what is in the file. However, when I try to read the file I get an exception:

Exception thrown at 0x7C3306DD (ucrtbased.dll) in MacroTool.exe: 0xC0000005: Access violation reading location 0x00000068.

Here is my code:

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

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("ERR: too few arguments.
");
        return 1;
    }
    if (argc > 2) {
        printf("ERR: too many arguments.
");
        return 1;
    }

    FILE* fp = fopen(argv[1], "r");

    if (fp == NULL) {
        printf("ERR: cannot read file.
");
        return 1;
    }

    char buf[100];

    char c;

    while ((c = fgetc(fp)) != EOF)
        strncat(buf, c, 1);

    fclose(fp);

    return 0;
}

Using multiple search engines to find an answer that is related to this issue led to nothing.

I am using windows 10 and visual studio 2019

question from:https://stackoverflow.com/questions/65865729/strncat-causes-exception

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are attempting to use a string-funciton on a buffer that is not nul-terminated resulting in Undefined Behavior. Specifically:

    char buf[100];

    char c;

    while ((c = fgetc(fp)) != EOF)
        strncat(buf, c, 1);

On your first call to strncat, buf in uninitialized resulting in Undefined Behavior due to strncat() replacing the existing nul-terminating character (which doesn't exist) with the new text to be appended. You can initialize buf all zero with:

    char buf[100] = "";

That will fix the immediate Undefined Behavior but will not prevent you later reading beyond the bounds of buf when you read past the 99th character.

Instead, declare a counter and initialize the counter zero, and use that to limit the number of characters read into your buf, as in the comment:

    size_t n = 0;
    
    while (n + 1 < 100 && (c = fgetc(fp)) != EOF) { 
        buf[n++] = c;
    }
    buf[n] = 0;      /* don't forget to nul-terminate buf */

You can put it altogether and avoid using Magic-Numbers (100) as follows:

#include <stdio.h>

#define MAXC 100        /* if you need a constant, #define one (or more) */

int main (int argc, char* argv[]) {
    
    if (argc < 2) { /* validate one argument given for filename */
        fputs ("error: too few arguments.
", stderr);
        return 1;
    }
    char buf[MAXC] = "", c;
    size_t n = 0;
    FILE* fp = fopen (argv[1], "r");

    if (fp == NULL) {                   /* validate file open for reading */
        perror ("fopen-argv[1]");       /* on failure, perror() tells why */
        return 1;
    }

    /* while buf not full (saving 1-char for ), read char */
    while (n + 1 < MAXC && (c = fgetc(fp)) != EOF)
        buf[n++] = c;                   /* assign char to next element in buf */

    buf[n] = 0;                         /* nul-terminate buf */
    
    puts (buf);                         /* output result */
    
    fclose(fp);
}

(note: the comparison with n + 1 ensures one-element in buf remains for the nul-terminating character)

Example Use/Output

$ ./bin/read100chars read100chars.c
#include <stdio.h>

#define MAXC 100        /* if you need a constant, #define one (or more) */

in

(note: the first 'n' in int main (... is the 99th character in the file)

Look thing over and let me know if you need further help. (note with VS you will likely need to pass /w4996 to disable the "CRT Secure...." warning.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...