Find the some smallest negative using Dynamic memory allocation in C

59 Views Asked by At

I'm doing my homework but there is some bugs I cannot fix Could you please help me? The question is using Dynamic memory allocation in C Find the some location of smallest negative element

The Function amnn is the "thing" I cannot fix

Thank u so much

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

int nhapmang (int *p,int n)
{
    int i;
    for (i=0;i<n;i++)
    {
        printf ("Nhap vao a[%d] = ",i);
        scanf ("%d",&*(p+i));
    }
}
int inmang (int *p,int n)
{
    for (int i=0;i<n;i++) 
    printf ("   %d",*(p+i));
}

int amnn(int *p, int n)
{
    int tg,tg1;
    for (int i=0;i<n;i++)
    {
        if (*(p+i)<0)
        {
        tg=*(p+i);
        break;
        }
    }
    for (int i=0;i<n;i++)
    {
    if (*(p+i)<0 && (tg>*(p+i)))
        {
        tg1=i;
        }
    }
    printf ("\nvi tri so am nho nhat trong mang la: a[%d]",tg1);
}
int main()
{
    int *p, n,a,amnn1;
    printf ("nhap vao n: ");
    scanf ("%d",&n);
    p=(int*)malloc(n*sizeof(int));
    nhapmang (p,n);
    printf ("\nin ma tran:");
    inmang(p,n);
    amnn(p,n);
return 0;
}

Input: n=5, a[0]=-9, a[1]=5, a[2]=-2, a[3]=-99, a[4]=-99 The result is a[3], a[4]

1

There are 1 best solutions below

7
Craig Estey On BEST ANSWER

Unfortunately, I didn't understand the logic of your amnn.

It appears to only handle the case where there is one minimum value, so it would not handle your sample input.

I had to completely refactor your code. It is annotated:

#include <stdio.h>
#include <stdlib.h>

// amnn -- find all minimum negative numbers
void
amnn(int *arr,int n)
{

    // number of indexes that contain the minimum value
    int mincount = 0;

    // list of indexes that contain the minimum value
#if ALLOC
    int *idxlist = malloc(sizeof(*idxlist) * n);
#else
    int idxlist[n];
#endif

    // current minimum value
    // start with a positive value to handle initial case
    int minval = 1;

    // loop through all array elements
    for (int curidx = 0;  curidx < n;  ++curidx) {
        int curval = arr[curidx];

        // we only want negative values
        if (curval >= 0)
            continue;

        // ignore values that are greater than the current minimum
        if (curval > minval)
            continue;

        // we have a new minimum value
        if (curval < minval) {
            // reset count of matching indexes
            mincount = 0;

            // set new minimum value
            minval = curval;
        }

        // current value is part of the set of minimum values
        if (curval == minval)
            idxlist[mincount++] = curidx;
    }

    // print results
    do {
        if (minval >= 0) {
            printf("no negative values found\n");
            break;
        }

        printf("minimum value is: %d\n",minval);

        printf("it is contained in indexes:\n");
        for (int listidx = 0;  listidx < mincount;  ++listidx)
            printf("  %d\n",idxlist[listidx]);
    } while (0);

#if ALLOC
    free(idxlist);
#endif
}

UPDATE:

why must reset mincount = 0 ? – Đinh Trọng Đạt

Perhaps, the better question to ask is:

What happens if we do not reset mincount = 0?

With the following sequence we would still get the correct answer (but only by luck):

-7 -6

However, if we have a list where the absolute/true minimum comes after a local/false minimum, without the reset, this will fail:

-6 -7

It will record/remember -6. When it sees -7, it will not remove -6 from the list.

Here is the code modified to test this assertion:

#include <stdio.h>
#include <stdlib.h>

int noreset;                            // 1=do _not_ reset count (testing)

// amnn -- find all minimum negative numbers
void
amnn(int *arr,int n)
{

    // number of indexes that contain the minimum value
    int mincount = 0;

    // list of indexes that contain the minimum value
#if ALLOC
    int *idxlist = malloc(sizeof(*idxlist) * n);
#else
    int idxlist[n];
#endif

    // current minimum value
    // start with a positive value to handle initial case
    int minval = 1;

    // loop through all array elements
    for (int curidx = 0;  curidx < n;  ++curidx) {
        int curval = arr[curidx];

        // we only want negative values
        if (curval >= 0)
            continue;

        // ignore values that are greater than the current minimum
        if (curval > minval)
            continue;

        // we have a new minimum value
        if (curval < minval) {
            // reset count of matching indexes
            if (! noreset)
                mincount = 0;

            // set new minimum value
            minval = curval;
        }

        // current value is part of the set of minimum values
        if (curval == minval)
            idxlist[mincount++] = curidx;
    }

    // print results
    do {
        if (minval >= 0) {
            printf("no negative values found\n");
            break;
        }

        printf("minimum value is: %d\n",minval);

        printf("it is contained in indexes:\n");
        for (int listidx = 0;  listidx < mincount;  ++listidx) {
            int arridx = idxlist[listidx];
            int curval = arr[arridx];
            printf("  arr[%d]=%d%s\n",
                arridx,curval,(curval != minval) ? " FAIL" : "");
        }
    } while (0);

#if ALLOC
    free(idxlist);
#endif
}

#define DOTEST(_data...) \
    do { \
        int arr[] = { _data }; \
        dotest(sizeof(arr) / sizeof(arr[0]),arr); \
    } while (0)

void
dotest(int n,int arr[n])
{

    printf("\n");
    for (int col = 1;  col <= 80;  ++col)
        printf("-");
    printf("\n");
    printf("dotest: n=%d\n",n);

    for (int arridx = 0;  arridx < n;  ++arridx)
        printf("dotest: arr[%d]=%d\n",arridx,arr[arridx]);

    printf("\nNORMAL:\n");
    noreset = 0;
    amnn(arr,n);

    printf("\nNORESET:\n");
    noreset = 1;
    amnn(arr,n);
}

int
main(void)
{

    DOTEST(-9, 5, -2, -99, -99);

    DOTEST(-7, -6);

    DOTEST(-6, -7);

    return 0;
}

Here is the program output:


--------------------------------------------------------------------------------
dotest: n=5
dotest: arr[0]=-9
dotest: arr[1]=5
dotest: arr[2]=-2
dotest: arr[3]=-99
dotest: arr[4]=-99

NORMAL:
minimum value is: -99
it is contained in indexes:
  arr[3]=-99
  arr[4]=-99

NORESET:
minimum value is: -99
it is contained in indexes:
  arr[0]=-9 FAIL
  arr[3]=-99
  arr[4]=-99

--------------------------------------------------------------------------------
dotest: n=2
dotest: arr[0]=-7
dotest: arr[1]=-6

NORMAL:
minimum value is: -7
it is contained in indexes:
  arr[0]=-7

NORESET:
minimum value is: -7
it is contained in indexes:
  arr[0]=-7

--------------------------------------------------------------------------------
dotest: n=2
dotest: arr[0]=-6
dotest: arr[1]=-7

NORMAL:
minimum value is: -7
it is contained in indexes:
  arr[1]=-7

NORESET:
minimum value is: -7
it is contained in indexes:
  arr[0]=-6 FAIL
  arr[1]=-7

As above, it can help to write code that checks the results for validity.

To help debug programs, we can also add extra printf statements that can show intermediate values and progress. To keep the code small and easy to read, I prefer to use a macro:

#if DEBUG
#define dbgprt(_fmt...) \
    printf(_fmt)
#else
#define dbgprt(_fmt...) \
    do { } while (0)
#endif

Then, when we want to see the debug output, we compile with -DDEBUG. Otherwise, the program runs normally (at full speed).