-4

I had written a program which is shown below the problem is that when I use gets() function then while executing the code in code blocks 16.01 when the gets function is called then suddenly the the code blocks stopped working. Can anyone help me out of this problem.


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

#define PI 3.1415926535897932384626433832795

struct elements
{
    float A, L, x1, y1, x2, y2;
    double deg, c, s, E, esm[4][4];
    int n1, n2;
} * ele;

int nonod, noele;
void elestiffmat(int);

void main()
{
    int i;
    char ch;
    printf("\nEnter the number of nodes you want to create:");
    scanf("%d", &nonod);
    printf("\nEnter the number of elements you want to create:");
    scanf("%d", &noele);
    if (noele < (nonod - 1))
    {
        printf("\nThe problem is wrongly modeled.\nPress any key to abort.");
        getch();
        exit(0);
    }
    ele = (struct elements*)malloc(noele * sizeof(struct elements));
    for (i = 0; i < noele; i++)
    {
        printf("\nCreating element %d", i + 1);
        printf("\nCross sectional area?");
        scanf("%f", &ele[i].A);
        printf("\nYoung's Modulus?");
        scanf("%Lf", &ele[i].E);
        printf("\nStarting node number?");
        scanf("%d", &ele[i].n1);
        printf("\nIts coordinates:");
        scanf("%f%f", &ele[i].x1, &ele[i].y1);
        printf("\nEnding node number?");
        scanf("%d", &ele[i].n2);
        printf("\nIts coordinates:");
        scanf("%f%f", &ele[i].x2, &ele[i].y2);
        ele[i].L = sqrt(pow((ele[i].x2 - ele[i].x1), 2) + pow((ele[i].y2 - ele[i].y1), 2));
        if ((ele[i].x2) - (ele[i].x1) == 0)
        {
            if (ele[i].y2 > ele[i].y1)
            {
                ele[i].deg = PI / 2.0;
            }
            if (ele[i].y2 < ele[i].y1)
            {
                ele[i].deg = (3.0 * PI) / 2.0;
            }
        }
        if ((ele[i].y2) - (ele[i].y1) == 0)
        {
            if (ele[i].x2 > ele[i].x1)
            {
                ele[i].deg = 0.0;
            }
            if (ele[i].x2 < ele[i].x1)
            {
                ele[i].deg = PI;
            }
        }
        if (((ele[i].y2) - (ele[i].y1)) / ((ele[i].x2) - (ele[i].x1)) < 0)
        {
            ele[i].deg = PI + atanf(((ele[i].y2) - (ele[i].y1)) / ((ele[i].x2) - (ele[i].x1)));
        }
        if (((ele[i].y2) - (ele[i].y1)) / ((ele[i].x2) - (ele[i].x1)) > 0)
        {
            ele[i].deg = atanf(((ele[i].y2) - (ele[i].y1)) / ((ele[i].x2) - (ele[i].x1)));
        }
        // printf("%g",ele[i].deg);
        ele[i].c = cos(ele[i].deg);
        ele[i].s = sin(ele[i].deg);
        // printf("c=%g\ts=%g",ele[i].c,ele[i].s);
        elestiffmat(i);
    }
    getch();
}
void elestiffmat(int i)
{
    char choice;
    ele[i].esm[0][0] = ele[i].c * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[0][1] = ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[0][2] = -ele[i].c * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[0][3] = -ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[1][0] = ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[1][1] = ele[i].s * ele[i].s * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[1][2] = -ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[1][3] = -ele[i].s * ele[i].s * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[2][0] = -ele[i].c * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[2][1] = -ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[2][2] = ele[i].c * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[2][3] = ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[3][0] = -ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[3][1] = -ele[i].s * ele[i].s * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[3][2] = ele[i].s * ele[i].c * ele[i].A * ele[i].E / ele[i].L;
    ele[i].esm[3][3] = ele[i].s * ele[i].s * ele[i].A * ele[i].E / ele[i].L;
    printf("\nDo you want to print the element stiffness matrix (y/n)?");
    gets(choice);
    if (choice == 'y' || choice == 'Y')
    {
        printf("\nThe element stiffness matrix of the element %d is:-", i + 1);
        int j, k;
        for (j = 0; j < 4; j++)
        {
            printf("\n");
            for (k = 0; k < 4; k++)
            {
                printf("%15g", ele[i].esm[j][k]);
            }
        }
    }
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • 3
    try using a char array for choice. As gets writes a string your char has to take more values than it can hold.... This should be shown in a warning I guess. – Kami Kaze Mar 01 '17 at 10:33
  • 6
    Before trying to fix this, *stop using* `gets`. It is vile, evil, and each time it's used somewhere a kitten dies. It was *removed* from the standard library and is no longer supported going forward. use [`fgets`](http://en.cppreference.com/w/c/io/fgets) instead. Second, `gets` takes a `char*` as a parameter, you're passing `char`, so on top of using a function you should not use, you're not using it as documented. I'd link the documentation, but that may encourage you keep using it, and ultimately you do *not* want to do that, even if you do. – WhozCraig Mar 01 '17 at 10:35
  • 5
    First of all, ***never ever*** use `gets`. It is a dangerous function that have been obsolete since the C99 standard and removed completely in the C11 standard. Use [`fgets`](http://en.cppreference.com/w/c/io/fgets) instead. Secondly, I doubt it is your IDE that has stopped working, but your program. To solve your problem start by using the debugger to find out *where* in your program the crash has happened, and check the values of involved variables. If you still can't figure it out, then tell us that information (location and variable values). – Some programmer dude Mar 01 '17 at 10:35
  • 2
    To expand on what WhozCraig and Someprogrammerdude said, read [Why is the gets function so dangerous that it should not be used](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – StoryTeller - Unslander Monica Mar 01 '17 at 10:36
  • While you should not use `gets`, it is your usage of it that causes the crash. Not because of the problems with `gets`, but because of you passing the wrong kind of argument to it. Your problem will not be solved by using `fgets`, but by using a function to read a single character. – Some programmer dude Mar 01 '17 at 10:37
  • 2
    Please read [about mcve](/help/mcve) and confirm that this indeed is the *the shortest code necessary*. – Antti Haapala -- Слава Україні Mar 01 '17 at 10:57
  • 2
    Your problems will be solved by you turning on compiler warnings and not ignoring them. – Antti Haapala -- Слава Україні Mar 01 '17 at 10:58
  • The question has been properly answered. But could you please also fix the construction of thestiffness matrix? It hurts the eye and is also prone to bugs – Ajay Brahmakshatriya Mar 01 '17 at 11:59
  • Please [edit] your code to reduce it to a [mcve] of your problem. Your current code includes much that is peripheral to your problem - a minimal sample normally looks similar to a good unit test: only performing one task, with input values specified for reproducibility. – Toby Speight Mar 01 '17 at 15:17

2 Answers2

2

If I rebuild (your code), I get the warning like this

enter image description here

then, try with scanf(" %c", &choice);

The %c conversion specifier won't automatically skip any leading whitespace, so if there's a stray newline in the input stream. the scanf call will consume it immediately.

One way around the problem is to put a blank space before the conversion specifier in the format string:

scanf(" %c", &choice);

The blank in the format string tells scanf to skip leading whitespace, and the first non-whitespace character will be read with the %c conversion specifier. The Check Rebuild, And I get no warning with this


  • Whenever gets() statement encounters then characters entered by user (the string with spaces) will be copied into the variable.
  • If user start accepting characters , and if new line character appears then the newline character will not be copied into the string variable(i.e name).
  • A terminating null character is automatically appended after the characters copied to string vriable (i.e name)
  • gets() uses stdin (Standered Input Output) as source, but it does not include the ending newline character in the resulting string and does not allow to specify a maximum size for string variable (which can lead to buffer overflows).

The gets() function has no means of preventing you typing the characters and so should be avoided.

I hope this use full. Sorry if any mistake :) I learner

0

I can't say why it "stopped working" on your system, although as it's been mentioned already, you're passing an incorrect parameter, so undefined behaviour is expected. See the following, from the man page:

char *gets(char *s);

DESCRIPTION

Never use this function.

gets() reads a line from stdin into the buffer pointed to by s until either a terminating newline or EOF, which it replaces with a null byte ('\0'). No check for buffer overrun is performed (see BUGS below).

So there were two mistakes, passing a char instead of a buffer pointer, and using gets in the first place. The manual further explains why it's so dangerous to use gets:

BUGS Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.

For more information, see CWE-242 (aka "Use of Inherently Dangerous Function") at http://cwe.mitre.org/data/definitions/242.html

Put it simply, suppose you had declared choice as follows:

char choice[2]; // e.g. 'y' plus terminating null byte

There's nothing stopping the user from entering "Yes" or anything else, which goes beyond the buffer size.

Remember that you would be passing a pointer, and every time you pass a pointer to a buffer, the receiving function should also receive the buffer size and ensure that it won't go past its boundary. Because this function does not take size as a parameter, it's now deprecated (read "forbidden" in this case).

Anyway, there are many alternatives, this is one potential solution.

Replace "char choice" with:

int choice, c;

And instead of "gets(choice)" you could use this:

while( (c = getchar()) != '\n' && c != EOF )
    /* discard */ ;
choice = getchar();

Note that "getchar() is equivalent to getc(stdin)". It doesn't actually read directly from the keyboard. That's why we've add the while loop to discard unprocessed data from the input stream, prior to the prompt. See this answer on c-faq for details.

Nagev
  • 10,835
  • 4
  • 58
  • 69