Can somone please explain this to me - c

For n=3 and a={1,2,3},b={4,5,6} its supposed to calculate 1*4+2*5+3*6.
I don't understand why does it work because p is a pointer and p=produs(a,b,n) means that the address of p becomes the value returned by produs.
#include <stdio.h>
#include <conio.h>
void citire(int *x,int *n)
{
for(int i=1; i<=*n; i++)
scanf("%d",&x[i]);
}
int produs(int *a,int*b,int n)
{
int produs=0;
for(int i=1;i<=n;i++)
produs=a[i]*b[i]+produs;
return produs;
}
int main()
{
int n;
int*p;
scanf("%d",&n);
int *a=(int*)malloc(n*sizeof(int));
int *b=(int*)malloc(n*sizeof(int));
citire(a,&n);
citire(b,&n);
p=produs(a,b,n);
printf("%d",p);
return 0;
}

When you do:
size_t size = 10;
int* x = calloc(size, sizeof(int));
You get an array x with 10 items in it, indexed 0..9, not 1..10. Here calloc is used to make it abundantly clear what's being requested instead of doing multiplication that can be mysterious or obtuse.
As such, to iterate:
for (int i = 0; i < size; ++i) {
x[i] ...
}
You have a number of off-by-one errors in your code due to assuming arrays are 1..N and not 0..(N-1).
Putting it all together and cleaning up your code yields:
#include <stdio.h>
#include <stdlib.h>
void citire(int *x, size_t s)
{
for(int i=0; i < s; i++)
scanf("%d", &x[i]);
}
int produs(int *a, int* b, size_t s)
{
int produs = 0;
for(int i = 0; i < s; i++)
produs = a[i] * b[i] + produs;
return produs;
}
int main()
{
int n;
scanf("%d",&n);
int* a = calloc(n, sizeof(int));
int* b = calloc(n, sizeof(int));
citire(a, n);
citire(b, n);
// produs() returns int, not int*
int p = produs(a,b,n);
printf("%d", p);
return 0;
}
You're using pointers in places where pointers don't belong. In C passing a pointer to a single value means "this is mutable", but you don't change those values, so no pointer is necessary nor advised.
Try and use size_t as the "size of thing" type. That's what's used throughout C and it's an unsigned value as negative indexes or array lengths don't make any sense.

Related

Printing a 2-D array in a function in C

I want to initialise and print a 2-D array in two separate functions, but i don't really know if i am doing this correctly.
I wrote 2 functions: int** matrix_initialization(int n, int m) and int print_matrix(int n1, int n2, int **a);
In the first function i have to arguments: int n - the number of rows and int m - the number of cols. In this function i initialise a pointer to the pointer int **matrix = NULL; Then i allocate memory to it, and giving this 2-D array random values.
Is that okay that the type of the int** matrix_initialization(int n, int m) function is int ** ?
The second function is int print_matrix(int n1, int n2, int** a) and there are some problems, the main is that it is not working. I have three arguments int n1 - rows, int n2 - cols, int** a a pointer to the pointer. This function is to print matrix.
Here is my code:
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <time.h>
int** matrix_initialization(int n, int m)
{
int** matrix = NULL;
matrix = (int**)malloc(n * sizeof(n));
if (matrix != NULL)
{
if (matrix != NULL)
{
for (int i = 0; i < m; i++)
{
*(matrix + i) = (int*)malloc(m * sizeof(m));
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = rand() % 20 - 5;
}
}
}
}
return matrix;
}
int print_matrix(int n1, int n2, int** a)
{
for (int i = 0; i < n1; i++)
{
for (int j = 0; j < n2; j++)
{
printf("%d\t", a[i][j]);
}
printf("\n");
}
}
int main()
{
srand(time(NULL));
int N, M, **a;
scanf_s("%d %d", &N, &M);
a = matrix_initialization(N, M);
print_matrix(N, M, a);
}
There are many issues with this code.
Major:
You aren't using 2D arrays but arrays of pointers. That doesn't make the slightest sense for this application, you are just making your code more complex, error prone and slow for absolutely nothing gained. See Correctly allocating multi-dimensional arrays.
matrix = (int**)malloc(n * sizeof(n)); Both of your malloc calls are strange, n is just a size parameter (could as well be size_t) and not necessarily of the same type as the data. Which is a int* in this case, not an int. You should be allocating something like matrix = malloc(n * sizeof(*matrix))
The first for loop for (int i = 0; i < m; i++) is wrong, should be n.
You aren't freeing allocated memory.
Minor:
locale.h isn't needed for this program.
There's no actual need to initialize your pointer matrix to NULL if you are to assign to it on the next line. Also you have multiple redundant checks vs NULL.
*(matrix + i) is never the best way to access an array in C, it's just an obscure way of writing matrix[i]. Don't complicate things just for the heck of it.
Don't name parameters n and m in one function and then n1 n2 in another function. Don't complicate things just for the heck of it.
Avoid functions ending with _s unless you have specific reasons why you need to use them. They are non-portable. It's very likely that whoever told you to use it has no idea what they are talking about. Including no idea about the whole "bounds-checking interface" debacle in C11.
int main() is obsolete style, always use int main (void) (as opposed to C++).
Here is a rewrite with all problems fixed, using 2D arrays instead:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void* matrix_initialization (int n, int m)
{
int (*matrix)[m] = malloc( sizeof(int[n][m]) );
if (matrix != NULL)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = rand() % 20 - 5;
}
}
}
return matrix;
}
void print_matrix (int n, int m, int a[n][m])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d\t", a[i][j]);
}
printf("\n");
}
}
int main (void)
{
srand(time(NULL));
int N, M;
scanf("%d %d", &N, &M);
int (*a)[M];
a = matrix_initialization(N, M);
print_matrix(N, M, a);
free(a);
}
You have two major problems:
The first is
malloc(n * sizeof(n))
which is the same as
malloc(n * sizeof(int))
And that makes no sense when you want to create an array of n pointers to int. On a 64-bit system it's unlikely that sizeof(int) == sizeof(int *).
It should be
malloc(n * sizeof(int*))
Or better yet
malloc(n * sizeof *matrix)
The second problem is your loop where you allocate the int arrays:
for (int i = 0; i < m; i++)
You have just created an array of n elements. Now you iterate over m elements? This will only work if n == m.
The correct loop should of course be
// Iterating over an array of n elements
for (int i = 0; i < n; i++)
You also have the same problem with the malloc call as mentioned above, but this time it just so happens to work because m is an int which is the right type and size.
On another few notes, in C you should not cast the result of malloc.
You never free any of the data you allocate, leading to memory leaks.
And instead of *(matrix + i) use matrix[i].
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <time.h>
int** matrix_initialization(int n, int m)
{
int** matrix = NULL;
//matrix = (int**)malloc(n * sizeof(n));
matrix = (int**)malloc(n * sizeof(int *));
if (matrix != NULL)
{
for (int i = 0; i < n; i++)//here is n,not m
{
matrix[i] = (int*)malloc(m * sizeof(int));
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = rand() % 20 - 5;
}
}
}
return matrix;
}
int print_matrix(int n1, int n2, int** a)
{
for (int i = 0; i < n1; i++)
{
for (int j = 0; j < n2; j++)
{
printf("%d\t", a[i][j]);
}
printf("\n");
}
return 0;
}
int main()
{
srand(time(NULL));
int N, M, **a,i;
scanf("%d %d", &N, &M);
a = matrix_initialization(N, M);
print_matrix(N, M, a);
//free all the memory
for (i = 0; i<N; i++) {
free(a[i]);
}
free(a);
return 0;
}

main.c: warning: passing argument of ‘’ from incompatible pointer type

I'm trying to pass and return a two-dimension dynamic array by parameter, however it always shows this warning I mentioned in the question. I know there's something wrong with the array parameter, but I couldn't find in any book or a website how to properly pass an array whose dimensions change. I've read similar questions to mine about the warning and it's mostly about adding a & in your pointer, which I haven't added in mine.
#include <stdio.h>
#include <stdlib.h>
void fun(int m, int n, int (*arr)[n]);
int main(void) {
int i, j, m, n, **arr;
printf("Enter the dimensions m, n\n");
scanf("%d %d", &m, &n);
arr = (int **)malloc(m * sizeof(int *));
for (i = 0; i < m; i++) {
arr[i] = (int *)malloc(n * sizeof(int));
}
fun(m, n, *arr);
printf("\n\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%5d", arr[i][j]);
}
printf("\n");
}
if (arr == NULL) {
exit(1);
} else
if (arr != NULL) {
free(arr);
}
return 0;
}
void fun(int m, int n, int (*arr)[n]) {
int i, j, k = 0;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
k = k + 1;
arr[i][j] = k;
}
}
}
int **arr;
In main, arr is a pointer to a pointer to integer and you populate it with a nested memory allocation, because there are two levels of pointers involved. The arr[i] can be fragmented and each could hold a different number of entries, making arr a "ragged" array.
int (*arr)[n]
The argument to your function is a pointer to an array of n integers. Here the entries of arr are contiguous in memory, so that arr[0] and arr[1] are sizeof(int[n]) bytes apart.
These are different types and the compiler tells you so. Pick one.
A You can stick with the pointer-to-pointer approach. Then your function signature must match the definition in main:
void fun(int m, int n, int **arr) ...
In that case, you must also free all arr[i] at the end, before free(arr).
B Alternatively, you can keep your curret function and create a contiguous array with a single allocation:
int (*arr)[n] = malloc(m * sizeof(*arr));
Then pass it to your function directly without dereferencing it:
fun(m, n, arr);
At the end, just free(arr).
You are passing pointer to int(that is *arr) but you have declared function that will get pointer to array of n integers.
So, just make the following changes:
void fun(int m, int n, int **arr); // also change where function definition begins
fun(m, n, arr);
By the way, freeing memory is incomplete.
for (i=0; i<m; i++)
free(arr[i]); // first free individual array elements
free(arr);
fun is defined as receiving a pointer to variable sized array or n int. This is a C99 specific syntax that some C compilers might not support. You could also have defined fun with a simpler and more readable prototype that is in fact equivalent:
void fun(int m, int n, int arr[m][n]);
Also equivalent to this one:
void fun(int m, int n, int arr[][n]);
The problem is you allocate a very different type of object: an array of m pointers to arrays of n int. You should instead allocate an array of m variable sized arrays of n int and store its address to a pointer with the appropriate type:
int (*arr)[n] = malloc(m * sizeof(*arr));
Or just define it as a 2D variable sized array with automatic storage:
int arr[m][n];
If allocated with malloc(), you would free the object with
free(arr);
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
void fun(int m, int n, int arr[m][n]);
int main(void) {
int i, j, m, n;
printf("Enter the dimensions m, n\n");
if (scanf("%d %d", &m, &n) != 2 || m <= 0 || n <= 0)
return 1;
int (*arr)[n] = malloc(m * sizeof(*arr));
if (arr == NULL)
return 1;
fun(m, n, arr);
printf("\n\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%5d", arr[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
void fun(int m, int n, int arr[m][n]) {
int i, j, k = 0;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
k = k + 1;
arr[i][j] = k;
}
}
}

Adding 2 matrices using pointers

I can acheive it by passing (c,a,b) to add_mat function, where result of a,b is stored in c like,
void add_mat(int c[][3], int a[][3], int b[][3], int m, int n)
What should be the return type of add_mat if I want to construct the funtion in this way
?? add_mat(int a[][3], int b[][3], int m, int n)
Below is a sample code
#include<stdio.h>
void read_mat(int a[][3], int m, int n){
//scan data
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
printf("[%d][%d] : ",i,j);
a[i][j]=i+j;
}
}
}
int* add_mat(int a[][3], int b[][3], int m, int n){
int c[3][3];
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
c[i][j]=a[i][j]+b[i][j];
}
}
return c;
}
int main(){
int a[3][3];
int m=2,n=2; //mxn of a matrix
read_mat(a, m, n);
//add
int b[3][3];
read_mat(b, m, n);
int* c[3][3];
c = add_mat(a,b,m,n);
return 0;
}
Like passing or pointing the calculated value c inside add_mat function to variable in main function.
You cannot do that, since the memory of the c matrix will be gone when the function terminates.
You need to dynamically allocate it with malloc(), in order for the memory not to be free'd, unless you call free(). I have some examples for that in 2D dynamic array (C), if you want to take a look.
With your previous function, you would create the matrix c outside the function (in main()), that's why dynamic memory allocation was not required.
PS: You should compile with warnings enabled:
prog.c: In function 'add_mat':
prog.c:19:12: warning: returning 'int (*)[3]' from a function with incompatible return type 'int *' [-Wincompatible-pointer-types]
return c;
^
prog.c:19:12: warning: function returns address of local variable [-Wreturn-local-addr]
prog.c: In function 'main':
prog.c:32:7: error: assignment to expression with array type
c = add_mat(a,b,m,n);
^
prog.c:31:10: warning: variable 'c' set but not used [-Wunused-but-set-variable]
int* c[3][3];
^
Here is a working example, which is just for demonstrative purposes:
#include <stdio.h>
#include <stdlib.h>
void read_mat(int a[][2], int n, int m){
//scan data
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
a[i][j] = i + j ;
}
}
}
int **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i, **table;
table = malloc(N*sizeof(int *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(int) );
return table;
}
void print(int** p, int N, int M) {
int i, j;
for(i = 0 ; i < N ; i++)
for(j = 0 ; j < M ; j++)
printf("array[%d][%d] = %d\n", i, j, p[i][j]);
}
void free2Darray(int** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}
int** add_mat(int a[][2], int b[][2], int m, int n){
int** c = get(n, m);
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
c[i][j]=a[i][j]+b[i][j];
}
}
return c;
}
int main(){
int n = 2, m = 2; //nxm of a matrix
int a[n][m];
read_mat(a, n, m);
//add
int b[n][m];
read_mat(b, n, m);
int** c;
c = add_mat(a, b, n, m);
print(c, n, m);
free2Darray(c ,n);
return 0;
}
Output:
array[0][0] = 0
array[0][1] = 2
array[1][0] = 2
array[1][1] = 4
PPS: If you really want to use static arrays, then I recommend using int c[3][3]; add_mat(c, a, b, m, n);
Oh yes, the pointers ...
In C, locally declared arrays usually are allocated on the stack (not on the heap) which means they are not valid outside the respective scope.
In other words, in your function add_mat(), c technically can be returned, but the address it points to will only contain meaningful matrix data as long as the function is executed.
After having returned from the function, the return value of the function is a pointer which still contains (points to) the address where the matrix was stored during execution of the function, but the contents of that location, i.e. the matrix data, can contain arbitrary garbage now.
So what you are doing is technically possible (i.e. throws no compile errors), but is definitely not what you want.
Secondly, your line int* c[3][3]; probably is not what you intend it to be. You are declaring c to be a two-dimensional array (matrix) of pointer to int here. This is not correct since you want to process int values, but not pointers to int values (which are addresses).
To solve both problems, just write int c[3][3]; instead of int* c[3][3]; and change your add_mat() function as follows:
void add_mat(int a[][3], int b[][3], int c[][3], int m, int n){
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
c[i][j]=a[i][j]+b[i][j];
}
}
}
Then call that function like that:
add_mat(a,b,c,m,n);
In your code add_mat returns the pointer to the variable which lives while the function executes only. You can accomplish your goal with dynamically allocated matrix.
In C it is common to pass a dynamically allocated matrix via pointer to pointers to the rows of matrix as a first parameter:
void foo(int** matrix, size_t m, size_t n);
Here matrix is a pointer to the array of pointers. Every pointer in this array points to the row of matrix. So, matrix[0] points to the array containing the first row of matrix.
And it is common to use size_t type for any sizes of arrays.
If you need create matrix dynamically, be careful with memory. Every dynamically allocated block should be released. Otherwise you will get memory leaks, that may cause the program crash. Therefore, when you allocate rows of matrix, you should check if allocation of current row was successfull. If not, you should release all previously allocated rows.
There is a working code for your question:
#include <stdio.h>
#include <stddef.h>
#include <malloc.h>
void free_mat(int** a, size_t m) {
if (!a) {
return;
}
for (size_t i = 0; i < m; ++i) {
free(a[i]);
}
free(a);
}
int** create_mat(size_t m, size_t n) {
int** rows = calloc(m, sizeof(int*));
if (!rows) {
return NULL;
}
for (size_t i = 0; i < m; i++) {
rows[i] = malloc(n * sizeof(int));
if (!rows[i]) {
free_mat(rows, m);
return NULL;
}
}
return rows;
}
void read_mat(int** a, size_t m, size_t n) {
for (size_t i = 0; i < m; i++) {
for (size_t j = 0; j < n; j++) {
printf("[%d][%d]: ", i, j);
scanf("%d", a[i] + j);
}
}
}
void print_mat(const int* const* a, size_t m, size_t n) {
for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < n; ++j) {
printf("[%d][%d]: %d\n", i, j, a[i][j]);
}
}
}
int** add_mat(const int* const* a, const int* const* b, size_t m, size_t n) {
int** c = create_mat(m, n);
if (c) {
for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < n; ++j) {
c[i][j] = a[i][j] + b[i][j];
}
}
}
return c;
}
int main() {
size_t m = 3;
size_t n = 3;
int** a = create_mat(m, n);
int** b = create_mat(m, n);
if (!a || !b) {
printf("error when allocating matrix\n");
}
else {
read_mat(a, m, n);
read_mat(b, m, n);
int** c = add_mat(a, b, m, n);
if (!c) {
printf("error when allocating matrix\n");
}
else {
print_mat(c, m, n);
free_mat(c, m);
}
}
free_mat(a, m);
free_mat(b, m);
return 0;
}
But you would be more flexible, if add_mat didn't create a new matrix.
It is common to pass a pointer to the result matrix as a function parameter:
void add_mat(int** c, const int* const* a, const int* const* b, size_t m, size_t n);

Creating a matrix with runtime dimentions as input

There are two cods that I have written. One works while the other wont. Please explain the working of this code wand why the latter isnt working.
Working -
#include <stdio.h>
#include <malloc.h>
int main(){
int m, n, i, j;
scanf("%d%d",&m,&n);
int *p;
p = (int *) malloc(m*n*sizeof(int));
for(i=0;i<m;i++){
for(j=0;j<n;j++){
scanf("%d", (p+i*n+j));
}
}
}
Not Working -
#include <stdio.h>
#include <malloc.h>
int main(){
int m, n, i, j;
scanf("%d%d",&m,&n);
int *p;
p = (int *) malloc(m*n*sizeof(int));
for(i=0;i<m;i++){
for(j=0;j<n;j++){
scanf("%d", p[i][j]);
}
}
}
error is - subscripted value is neither array nor pointer nor vector
scanf("%d", p[i][j]);
For the second example then p would need to be a pointer to an array, or a pointer to pointer.
It could be something like
int **p = malloc(m * sizeof(int *));
for (size_t i = 0; i < m; ++i)
{
p[i] = malloc(n * sizeof(int));
for (size_t j = 0; j < n; ++j)
{
scanf("%d", &p[i][j]);
}
}

Nothing works - references, pointers

void load(int *n, int *x, int **arr)
{
arr = (int**)malloc(sizeof(int*)*(*n));
for(int i = *n; i >= 0; i--)
{
scanf("%d", &arr[i]);
}
}
int main()
{
int n = 0, x = 0;
int *arr;
load(&n, &x, &arr);
printf("%d", arr[1]);
return EXIT_SUCCESS;
}
The program compiles properly, but it throws windows error during the printf() in main function. Displaying just "arr" gives random big numbers. What is wrong here?
arr = (int**)malloc(sizeof(int*)*(*n));
doesn't change anything in main, it only overwrites the copy of the pointer (address of arr in main) that load receives.
What the function should do is change arr in main, for that, you have to dereference the argument,
*arr = (int*)malloc(sizeof(int)*(*n)); // cast for C++ compiler left in
to change the value of arr in main. (The object that the argument arr of load points to, that is arr in main, needs to be changed, hence you need to modify *arr in load.)
The scans should then be
scanf("%d", &(*arr)[i]);
or (equivalent)
scanf("%d", *arr + i);
#include <stdio.h>
#include <stdlib.h>
void load(int *n, int *x, int **arr)
{
int i = 0;
*arr = (int*) malloc(*n * sizeof(int));
if(!*arr) {
perror("Can not allocate memory!");
return;
}
for(i = *n; i >= 0; i--)
{
scanf("%d", *arr + i);
}
return;
}
int main()
{
int n = 0, x = 0;
int *arr;
int i;
/* You probably need to initialize n */
n = 5;
load(&n, &x, &arr);
for(i = n; i >= 0; i--)
{
printf("%d - %d\n", i, arr[i]);
}
return EXIT_SUCCESS;
}

Resources