Search code examples
cdynamic-memory-allocation

Find the some smallest negative using Dynamic memory allocation in C


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]


Solution

  • 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).