-3

I'm working on a code which ask user to type the number of rows and columns for 2 matrices and later ask user to type its elements.

After taking the user input for elements of matrices. The function matadd is called which receives the addresses of array variable a[20][20], b[20][20] containing elements of first and second matrix, address of variables m, n containing no. of rows and columns, address of array variable s[20][20] which is going to store the sum of two matrices.

matadd function code :

int matadd(int *(h)[20], int *(k)[20], int *u, int *l,int *(m)[20])
{
//VARIABLE-DECLARATION
int i = 0, j = 0;

for (i = 0; i < *u; i++)
{
    for (j = 0; j < *l; j++)
    {
        *(*(m + i) + j) = *(*(h + i) + j) + *(*(k + i) + j);
    }
}

printf("The Addition of above two given matrices is given below :\n");

printf("--           --\n");
for (i = 0; i < *u; i++)
{
     for (j = 0; j < *l; j++)
    {
        printf("|");
        for (j = 0; j < *l; j++)
        {
            printf("%4d", *(*(m + i) + j));
        }
        printf(" | ");
        printf("\n");
    }
}
printf("--           --\n");

return(m);

}

The problem comes at this line of code *(*(m + i) + j) = *(*(h + i) + j) + *(*(k + i) + j); where it has to assign the added value one by one inside pointer variable m.

But program stops there and give me error :

Exception thrown at 0x00C124B9 in mATRIX_pROTO.exe: 0xC0000005: Access violation reading location 0x00000001.

If there is a handler for this exception, the program may be safely continued.

Not able to find whats wrong with the code. I am using Visual Studio 2015 for debugging my code.

Any help would be appreciated.

Here's my code :

//CONSTANT-VARIABLE
#define MAX 1000

//USER-DEFINED FUCNTION
int matadd(int *h, int *k, int *u, int *l,int *(m)[20]);
char xgets(char *line, int size, FILE *stdi);
void header(void);

char xgets(char *line, int size, FILE *stdi) {
  /* read a line from the user */
 fgets(line, size, stdi);

  /* strip the \n if present */
  line[strcspn(line, "\n")] = '\0';
 return line;
}

void header(void)
{
printf("*-*-*-*-*MATRIX_ADD_PTR*-*-*-*-*");
printf("\n\n");
}

//PROGRAM STARTS HERE
int main(void)
{
 //FUCNTION CALL-OUT
header();

//VARIABLE-DECLARATION
int a[20][20] = { { 0 } }, b[20][20] = { { 0 } }, c[20][20] = { { 0 } },s[20][20] = { {0} };
int i = 0, j = 0;
int m = 0, n = 0, q = 0, w = 0;
int line[MAX] = { 0 };

printf("Type Same Number of ROWs And COLUMNs for Both Matrx \n\n");

printf("Enter the No. of ROWs needed in First Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &m);
printf("\n");

printf("Enter the No. of COLUMNs needed in First Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &n);
printf("\n");

printf("Enter the Elements for 1st ROW then 2nd and So on for First Matrix : \n");
for (i = 0; i < m; i++)
{
    for (j = 0; j < n; j++)
    {
        xgets(line, sizeof(line), stdin);
        sscanf_s(line, "%d", &a[i][j]);
    }
}

printf("\n");

printf("Enter the No. of ROWs needed in Second Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &q);
printf("\n");

printf("Enter the No. of COLUMNs needed in Second Matrix : ");
xgets(line, sizeof(line), stdin);
sscanf_s(line, "%d", &w);
printf("\n");

printf("Enter the Elements for 1st ROW then 2nd and So on for Second Matrix : \n");
for (i = 0; i < q; i++)
{
    for (j = 0; j < w; j++)
    {
        xgets(line, sizeof(line), stdin);
        sscanf_s(line, "%d", &b[i][j]);
    }
}

//OUTPUT OF ENTERED MATRIX
printf("First Matrix : \n\n");

printf("--        --\n");
for (i = 0; i < m; i++)
{
    printf("|");
    for (j = 0; j < n; j++)
    {
        printf("%3d", a[i][j]);
    }
    printf(" | ");
    printf("\n");
}
printf("--        --\n\n\n");

printf("Second Matrix : \n\n");

printf("--        --\n");
for (i = 0;i < q;i++)
{
    printf("|");
    for (j = 0; j < q; j++)
    {
        printf("%3d", b[i][j]);
    }
    printf(" | ");
    printf("\n");
}
printf("--        --\n\n\n");

//FUCNTION CALL-OUT
matadd(a, b, &m, &n, s);

//TERMINAL-PAUSE
system("pause");
}


int matadd(int *(h)[20], int *(k)[20], int *u, int *l,int *(m)[20])
{
    //VARIABLE-DECLARATION
    int i = 0, j = 0;

    for (i = 0; i < *u; i++)
{
        for (j = 0; j < *l; j++)
     {
        *(*(m + i) + j) = *(*(h + i) + j) + *(*(k + i) + j);
     }
 }

printf("The Addition of above two given matrices is given below :\n");

printf("--           --\n");
for (i = 0; i < *u; i++)
{
    for (j = 0; j < *l; j++)
     {
        printf("|");
        for (j = 0; j < *l; j++)
         {
            printf("%4d", *(*(m + i) + j));
         }
        printf(" | ");
        printf("\n");
    }
}
printf("--           --\n");

return(m);

}
Eddy
  • 344
  • 5
  • 16
  • `int *(h)[20]` etc. are **no** 2D arrays (aka matrices). It decays to a pointer to pointer, which cannot be a 2D array. Maybe you mean `int (*h)[20]` Which can be used for a 2D array. Also don't uise _magic numbers_. They eventually will result in errors once your code grows. – too honest for this site Feb 21 '16 at 12:31
  • 1: Name. Your. Variables. And. Parameters. 2: Your function prototype and it's definition don't match. – Daniel Jour Feb 21 '16 at 12:34
  • The code does not even compile, `xgets` is supposed to return a `char` but tries to return a `char *` (line) instead. – Martin Zabel Feb 21 '16 at 12:37
  • @olaf yea I declared them so I can use them for a 2D array and I won't use any magic numbers will take care of that one ;) thnx for replying. – Eddy Feb 21 '16 at 12:37
  • @MartinZabel Code is getting compiled perfectly no issues with it. – Eddy Feb 21 '16 at 12:39
  • Then you must have posted the wrong code. My Visual Studio Compiler complains about the line given in my previous comment. – Martin Zabel Feb 21 '16 at 12:41
  • 2
    Enable *all* warnings, and treat every single one of them as error. Which compiler are you using? – Daniel Jour Feb 21 '16 at 12:41
  • @DanielJour Sorry about the function prototype and it's definition - I forgot to edit properly :) – Eddy Feb 21 '16 at 12:41
  • You might have intended to pass a 2D array, but they are wrong for that! And `#define MAX 1000` is not a "constant variable", but a text-macro **with** an _integer literal_ (it is just that the C standard calls this "integer constant") **very** different! – too honest for this site Feb 21 '16 at 12:42
  • @MartinZabel Right click on your project > Properties > C/C++ below configuration properties > All Option > Compile As : Compile as C Code (T/C). Please do the following I hope it will work. – Eddy Feb 21 '16 at 12:44
  • @Olaf I'm learning C from ANSI C book and it says #define instruction defines value to a symbolic constant for use in program. My bad - next time I will add comment line : //SYMBOLIC - CONSTANT :D – Eddy Feb 21 '16 at 12:48
  • @Olaf And Why it's wrong to pass 2D array? – Eddy Feb 21 '16 at 12:49
  • Your book is wrong! C does not support symbolic constants except for enum-constants (which are always type `int`). Macro replacement is done at a very different stage of the translation process. Note I did not say this is the way to go (because exactly because the lack of symbolic constants); it is just the semantics which are different. – too honest for this site Feb 21 '16 at 12:51
  • @Olaf Ok bro thanks. Can you suggest me a better book for ANSI Cthan this? – Eddy Feb 21 '16 at 12:54
  • No, I use the [standard](http://port70.net/~nsz/c/c11/n1570.html) (the link is the final draft actually, which is identical to the standard except for two very minor corrections - the actual standard is not free of charge. Find a pdf version yourself, just in case the link goes down). Maybe a bit hard to read for a beginner, though. – too honest for this site Feb 21 '16 at 13:01
  • @Olaf Thnx once again ;) – Eddy Feb 21 '16 at 13:02
  • If you are using Visual Studio as I think you are then it does not have a C compiler. It will be a C++ compiler if you want a c compiler there are gcc or clang. Code that will work for you might not compile with an actual C compiler. – Careful Now Feb 21 '16 at 15:59
  • Ok, I have found the switch now to turn the Visual Studio C++ compiler into a C compiler. After including `stdlib.h`, `stdio.h` and `process.h` (as you mentioned elsewhere) , it compiles, but a lot of serious warnings are issued by the compiler. One of it is: _warning C4013: `strcspn` undefined; assuming extern returning int_. – Martin Zabel Feb 21 '16 at 16:14
  • @MartinZabel If it's just a warning then ignore it and go type values and if possible please let me know why this code ain't working. – Eddy Feb 21 '16 at 16:53
  • @DanielDowd @MartinZabel Out of curiosity: Is there now a switch to compile C (and not just an "emulation" of it like `extern "C" {}` is) with Microsoft products? (I'm a Linux only user) – Daniel Jour Feb 21 '16 at 18:15
  • @DanielJour There is a switch called '/TC' which does even more than just `extern "C" {}`. – Martin Zabel Feb 21 '16 at 19:47
  • I have turned my "long comment" into a real answer now. It shows, that you cannot simply ignore warnings. – Martin Zabel Feb 21 '16 at 19:47
  • @DanielJour as far as I am aware it will compile C as any C++ compiler should, but it doesn't follow C standards. – Careful Now Feb 22 '16 at 09:32

2 Answers2

2

Looking at your addition code, we see this pattern three times:

*(*(h + i) + j)

The above expression should be of type int in order to make sense in the context of element wise addition. That means that

(*(h + i) + j)

should be of type int *, I.e. a pointer to an integer. This also means that j should be meaningfully convertible to size_t (it is) and that

*(h + i)

should also be of type int *. Then

(h + i)

should be a pointer to the above type, thus a int **. similar to above i should be convertible to size_t (which it is) and h should've the same type.

More directly speaking, it should be a pointer to (an array of) pointer(s) to (an array of) int(s).

Let's see what you have in main:

int a[20][20];

That's an array of arrays, thus except for indexing similar to

int a[20*20];

in that it's stored in contiguous memory. That's a different representation as above!

You need to decide on one of these representations.

I try to visualise this using a smaller, 2 on 2 situation (I'm on a mobile, thus this will be hard enough this way):

data:
1 2
3 4

Your function is expecting your data like that:

@some_address:
  address_one <--- h points to this
  address_two

@address_one:
  1
  2

@address_two:
  3
  4

But you have it stored like that:

@some_address:
  1 <--- a decays to a pointer pointing to here upon use
  2
  3
  4

Thus, your function uses the values 1 and 2 as memory addresses.

Note that I'm only addressing the (IMHO) main issue here, there are a lot more things to fix, as the example compiler messages in the other answer show.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • Thnx for replying Daniel. But I didn't understood what exactly you want to say, Can you elaborate it? – Eddy Feb 21 '16 at 13:16
  • I'm sorry - I understood 50% of what you trying to explain - If you don't mind can you please edit my C code with fix and post it? – Eddy Feb 22 '16 at 10:20
  • And I also wanted to say that my code do not show me any kind of warnings and errors when I run it in my Visual Studio 2015. – Eddy Feb 22 '16 at 10:26
1

You cannot just ignore all the warnings issued by the Visual Studio Compiler. After adding the mentioned includes stdlib.h, stdio.h and process.h and adding the switch /TC to the compiler call, the following warnings

warning C4047: 'function' : 'int *' differs in levels of indirection from 'int [20][20]'

warning C4024: 'matadd' : different types for formal and actual parameter 1

at the line

matadd(a, b, &m, &n, s);

clearly indicate that something is going wrong in your code. These warnings are issued because your function prototype expect a int * where you have given a int [20][20] in the call. Nevertheless, the function prototype does not match your definition of matadd. If I change the prototype to

int matadd(int *(h)[20], int *(k)[20], int *u, int *l,int *(m)[20]);

the compiler issues the following warnings instead:

warning C4047: 'function' : 'int **' differs in levels of indirection from 'int [20][20]'

warning C4024: 'matadd' : different types for formal and actual parameter 1

You can fix it by the changing the prototype and definition to:

int matadd(int (*h)[20], int (*k)[20], int *u, int *l,int (*m)[20]);

EDIT: The type int (*h)[20] actually represents a pointer to an array with 20 elements. If you add 1 to the pointer and dereference it with (*(h+1)), then you get the next 20 elements after the first 20 elements pointed to by (*h), and so on. You can also express it with the declaration int h[][20] which shows better the intended usage as a 2D array. Note, only the size of the first dimension can be left undefined. (There are even more possibilities as discussed here and here, but Visual Studio 2010 do not support these.)

EDIT: You can implement the matadd function without any explicit pointer arithmetic. This is a stripped down example:

#include <stdio.h>

// specifying the size of the first dimension is optional
void matadd(int h[][20], int k[][20], int u, int l, int m[][20])
{
    int i = 0, j = 0;

    for (i = 0; i < u; i++)
    {
        for (j = 0; j < l; j++)
        {
            m[i][j] = h[i][j] + k[i][j];
        }
    }
}

int main(void)
{
    int i, j, m, n;
    int a[20][20] = { { 0 } }, b[20][20] = { { 0 } }, s[20][20] = { {0} };

    m = 2; n = 2;
    a[0][0] = 1; a[0][1] = 2; a[1][0] = 3; a[1][1] = 4;
    b[0][0] = 5; b[0][1] = 6; b[1][0] = 7; b[1][1] = 8;

    matadd(a, b, m, n, s);

    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            printf("%4d | ", s[i][j]);
        }
        printf("\n");
    }
}

Your code even needs more fixes as indicated by compiler warnings;

warning C4013: 'strcspn' undefined; assuming extern returning int

because you forgot to include string.h.

warning C4047: 'function' : 'char' differs in levels of indirection from 'char *'

at return line; and return(m);. Here, you are converting a pointer to a character. The program does not segfault here because you happily did not use the return value.

warning C4133: 'function' : incompatible types - from 'int [1000]' to 'char *' warning C4133: 'function' : incompatible types - from 'int [1000]' to 'const char *'

at the calls of xgets and sscanf_s. This type conversion is also invalid. The program does not segfault, because the int [1000] is happily larger than a corresponding char [1000].


My previous long comment which was the starter of the discussion in the comments can be found here.

Community
  • 1
  • 1
Martin Zabel
  • 3,589
  • 3
  • 19
  • 34
  • Code is running perfectly martin I don't know whats the problem with your Visual Studio. Please check once again. – Eddy Feb 21 '16 at 12:52
  • @Eddy Of course, the invalid return type of `xgets` is only warning now. But the incompatible types in the declaration and definition `matadd` as well as the too many arguments in the call of that function are still **errors** which should even be reported by Visual Studio. – Martin Zabel Feb 21 '16 at 12:56
  • add this header files to my code at the top //HEADER FILES #include #include #include – Eddy Feb 21 '16 at 12:59
  • 1
    @Eddy This is a clear indication that you have posted the wrong code. Your code requires `string.h` for `strcspn`. I have added this along with `stdlib.h` and `stdio.h` and got the above result. `process.h` is Microsoft specific, but it seems not required here. – Martin Zabel Feb 21 '16 at 13:04
  • Don't add string.h header file - code works like butter without it. If you ask why to not add that header file then please don't ask because I have been discussing about it on some other post and came to this decision. – Eddy Feb 21 '16 at 13:09
  • This is part of your problem to begin with. In your code posted above there is no reference to include any headers whatsoever. Also Microsoft does not have a C compiler so you should probably try to use some C++ in there. – Careful Now Feb 21 '16 at 15:52
  • `int h[20][20]` as function parameter should decay to `int (*h)[20]` as you cannot pass arrays around (nor return them from functions or "store" them in variables, they're not first class values in C) – Daniel Jour Feb 21 '16 at 20:47
  • 1
    @DanielJour Yes, I know that an array decays into a pointer. I also mentioned `int (*h)[20]` as a first fix. The intention of my longer example was to show that one can implement `matadd` without any **explicit** pointer arithmetic. I clarified this in my answer. – Martin Zabel Feb 21 '16 at 21:31
  • @MartinZabel Listen man when I run my code I just don't see a single warnings or errors. After you copy code and paste it in your Visual Studio it always gives some errors. Check semi-colons and other stuff. My code is working totally fine and stop giving my question bad rating. I can't see where the hell I have made a mistake in writing this question - I know my english is bad but whatever I wrote is understandable and defines whats my problem. – Eddy Feb 22 '16 at 10:11
  • @Eddy I have removed my downvote because the code compiles now. But, the other downvotes came from other guys. I can't tell why you see no warnings or errors. Anyway, does my fix help (just above the first edit)? – Martin Zabel Feb 22 '16 at 10:23
  • @MartinZabel Ofc your code will work but the thing is I want to use pointer variables in that `matadd` function ( for a, b, m, n, s). If we do so h will get address of array variable a - k will get address of b and m will get address of array variable s which has 0 value and is suppose to store added value of two matrix. In the statement where it adds values in user-defined function `matadd` It adds two matrices a and b using pointers h and k(by using address) and stores the value inside pointer m. Thats what this code is supposed to do. – Eddy Feb 22 '16 at 10:39
  • @MartinZabel I hope you understood what i'm trying to explain martin. – Eddy Feb 22 '16 at 10:41
  • 1
    @Eddy Yes, I understood. And you have to change at least the function signature to `int matadd(int (*h)[20], int (*k)[20], int *u, int *l,int (*m)[20]);`. With this change, your code works. You can leave the pointer arithmetic inside the function as it is. – Martin Zabel Feb 22 '16 at 11:27
  • @MartinZabel Thnx alot for the help I really appreciate it - I found what was wrong with the code. :) – Eddy Feb 22 '16 at 11:49