I have a function I would like to have a function to receive a 2D array (H), to read a specified column (col) and to pass it to another array (b).
It appears that the code below is not OK has I was expecting to get a 1 printed.
Any guidance is very much appreciated.
#define nline 5
#define ncol 4
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
void count0(int **M,int col, int *a);
void main(){
int i;
int **H;
H=(int**)malloc(nline*sizeof(int*));
for(i=0;i<nline;i++){
H[i]=(int*)malloc(ncol*sizeof(int));
}
H[0][0]=8;
H[0][1]=5;
H[0][2]=6;
H[0][3]=0;
H[1][0]=7;
H[1][1]=5;
H[1][2]=4;
H[1][3]=0;
H[2][0]=5;
H[2][1]=1;
H[2][2]=1;
H[2][3]=7;
H[3][0]=0;
H[3][1]=0;
H[3][2]=0;
H[3][3]=2;
H[4][0]=1;
H[4][1]=0;
H[4][2]=1;
H[4][3]=4;
int *b;
int col=1;
count0(H,col,&b);
printf("num 0=%d\n",b[2]); getchar();
}
/////////////////////////////////////////////////////////////////////////////////
void count0(int **M,int col, int *a){
int i;
a=(int*)malloc(1*sizeof(int));
for(i=0;i<nline;i++){
a[i]=M[i][col];
a=realloc(a,(i+2)*sizeof(int));
}
}
Your argument for the output b is wrong. It needs to be a pointer to a pointer (like how you pass it). Right now you should get a compiler warning about it. The function prototype should be
void count0(int **M,int col, int **a);
Then in the function you need to use the dereference operator to access a:
*a = malloc(1*sizeof(int));
Note that I don't cast the return value of malloc, there no need to and neither should you.
As you already knows the number of rows = nline in your matrix in count0 function. So you should simply allocate all memory for array a in count function one time, you don't need to re-call realloc() function.
void count0(int **M, int col, int** a){
(*a) = malloc(nline * sizeof(int));
for(i = 0; i < nline; i++){
(*a)[i] = M[i][col];
}
}
Note: precedence of [] is higher then * so you need () around *a
just call this function as: count0(H, col, &b);
and free(b); in main() after printf statement to deallocate memory explicitly.
You are trying to have this variable:
int * b;
Point to an newly allocated array after this call:
count0(H,col,&b);
To do this, you must change the signature of count 0 to the following:
void count0(int **M,int col, int **a);
Note that int *a is now int **a. Then in the body of count0, you must use the following lines to allocate/reallocate a:
*a=(int*)malloc(1*sizeof(int));
*a=realloc(a,(i+2)*sizeof(int));
Right now, a is a pointer variable that only exists in the scope of count0. Initially its value is &b (which right now doesn't make sense since &b is an int**, and a is an int*). You have a point to newly allocated memory, which is lost after the function. The changes I suggest will have *a, and therefore b, to point to memory that can be retrieved after the function call.
Related
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 1 year ago.
#include<stdio.h>
#include <stdlib.h>
void deal_queries(int *arr, int limit, int numQueries, int filled) {
// Write your code here
for(int i=0;i<filled;i++)
{
printf("%d ",*(arr+0));
}
}
int * read_input(int N,int n){
//declare dynamic array of size N
// take input n integers and store them in the array and return pointer to this
int i;
int *ptr;
int array[N];
ptr=array;
for(i=0;i<n;i++)
{scanf("%d ",ptr);ptr++;}
ptr=array;
return (ptr);
}
int main()
{
int N,Q,n;
scanf("%d %d %d",&N,&Q,&n);
int* arr=read_input(N,n);
printf("%d ",*(arr+0));
deal_queries(arr,N,Q,n);
return 0;
}
when I print arr elements in main function I get correct values but if I pass them into deal with queries function I get random values can anyone explain why is this happening?
The variable array is local to read_input, so its life ends when returing from the function and accessing it after that is illegal.
Instead of that, you should allocate an array on the heap and use that.
#include<stdio.h>
#include <stdlib.h>
void deal_queries(int *arr, int limit, int numQueries, int filled) {
// Write your code here
for(int i=0;i<filled;i++)
{
printf("%d ",*(arr+0));
}
}
int * read_input(int N,int n){
//declare dynamic array of size N
// take input n integers and store them in the array and return pointer to this
int i;
int *ptr;
int *array=malloc(sizeof(*array)*N); /* allocate an array on the heap */
if(array==NULL) return NULL; /* check if allocation succeeded */
ptr=array;
for(i=0;i<n;i++)
{scanf("%d ",ptr);ptr++;}
ptr=array;
return (ptr);
}
int main()
{
int N,Q,n;
scanf("%d %d %d",&N,&Q,&n);
int* arr=read_input(N,n);
if(arr==NULL) return 1; /* check if allocation succeeded */
printf("%d ",*(arr+0));
deal_queries(arr,N,Q,n);
free(arr); /* free allocated array */
return 0;
}
You return the pointer to the local automatic storage variable which is UB as the variable stops existing when the function returns.
int array[N];
ptr=array;
for(i=0;i<n;i++)
{scanf("%d ",ptr);ptr++;}
ptr=array;
return (ptr);
You need to make it static (bad way) or dynamically allocate the memory
static int array[N];
ptr=array;
or better
//int array[N];
ptr=malloc(sizeof(*ptr)*N);
The error is in read_input where you have:
int array[N];
ptr=array;
return (ptr);
The variable array is a local variable in the function. And the assignment to ptr makes it point to the first element of this local array. This pointer will become invalid as soon as the function returns and the life-time of array ends.
You need to allocated the array dynamically using malloc instead:
int *array = malloc(N * sizeof *array);
int *ptr = array;
// Fill array using the ptr variable...
return array;
The pointer isn't a problem, it's what it points to. Here is the issue:
int * read_input(int N,int n) {
...
int array[N]; // This array is in automatic memory,
ptr=array; // so it is valid only inside read_input
...
return (ptr); // you are returning a pointer to it
}
In order to do what you want to do you need to use malloc:
int* ptr = malloc(sizeof(int)*N);
Use another pointer in the loop, or apply indexing to ptr, like this:
for (i = 0 ; i < n ; i++) {
scanf("%d ", &ptr[i]);
}
I am currently doing the fifteen exercise in CS50's Problem set 3. However, I am stuck in figuring out the syntax to pass a multi-dimensional array as an argument to a function. For instance, the following code (which prints out some numbers in an array) compiles and works:
#include <stdio.h>
void func(int array[], int size);
int main()
{
int size = 3;
int array[3] = {1,2,3};
func(array,size);
printf("Done\n");
}
void func(int array[], int size)
{
printf("%i %i %i\n", array[0],array[1], array[2]);
}
But this doesn't:
#include <stdio.h>
void func(int array[][], int size);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}
void func(int array[][], int size)
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}
This is the error provided by clang:
test.c:3:20: error: array has incomplete element type 'int []'
void func(int array[][], int size);
^
test.c:13:20: error: array has incomplete element type 'int []'
void func(int array[][], int size)
Can anyone explain to me what's wrong with my syntax? I don't quite understand the error messages given to me by clang.
The function func() expects a pointer to int but you are passing a pointer to an array. Hence, the errrors.
It's because an array gets converted into a pointer to its first element when you pass it to a function.
You can change the function prototype and definition to receive a pointer to an array:
void func(int (*array)[3], int size);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}
void func(int (*array)[3], int size) {
...
}
Note that your array is initialized with size 3x3. So the array size has to 3x3 at least.
C99 allows to you pass dimensions. So you can write it like this too:
void func(int x, int y, int a[x][y]);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(3, 3, array);
printf("Done");
}
void func(int x, int y, int array[x][y])
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}
An array is not a type in C! Internally, it is always handled as a pointer, hence, a pointer to the array is passed as argument and not the array itself.
If you intend to pass arrays as arguments (and not just pointers), you should rethink your design!
If you still need to do this wrap the array into a structure and pass the structure.
struct astruct
{
int size;
int array[3];
};
A declaration like int a[][] isn't sensible, since the compiler must know the size of all dimensions (except of the outermost) to calculate the memory address on access.
I.e. if an array is declared as
int array[][a][b];
The memory address for access to
array[2][1][3];
is calculated by
base_address + (2*a*b + 1*b + 3) * sizeof int
Without knowing a and/or b, this calculation would not be possible.
Simply tell the function to expect a multi-dimensional array:
void func (int array[3][3], int size);
Or if you want the function to be completely flexible:
void func (int x, int y, int array[x][y]);
You need to specify size of array when declaring prototype as well as while defining function . Right now it is of incomplete type .
Try this instead -
void func(int array[][3], int size)
I am new to pointers.
For the below program , I get an answer of 255 and not 20. Please suggest how to correct.
Here is the code :
int sum(int *a , int *b);
int main()
{
int *p;
int *q;
*p =10;
*q =10;
int c = sum(p,q);
printf("%d",c);
}
int sum(int *a , int *b)
{
return((*a)+ (*b));
}
There is data, then there are pointers. For simplicity, once you have data, then you can point to it. This is accomplished by using the & operator. To go back to the data from a pointer, use the * operator as you have
Something more like
int sum(int *a , int *b);
int main()
{
int p_data=10;
int q_data=10;
int *p =&p_data;
int *q =&q_data;
int c = sum(p,q);
printf("%d",c);
}
int sum(int *a , int *b)
{
return((*a)+ (*b));
}
EDIT: Also note that pointers can be used to access memory allocated from malloc, or mmap'd, or other means
You need to alloc memory for pointers. This code should work:
#include <stdio.h>
#include <stdlib.h>
int sum(int *a , int *b);
int main()
{
int *p = (int*) malloc(sizeof(int));
int *q = (int*) malloc(sizeof(int));
if (p != NULL && q != NULL)
{
*p =10;
*q =10;
int c = sum(p,q);
printf("%d", c);
free(p);
free(q);
}
else
{
printf("Could not allocate enough memory");
return 1;
}
return 0;
}
int sum(int *a , int *b)
{
return (*a) + (*b);
}
Hope this helps!
A pointer is a variable that holds the address of another variable, and this seems clear to you. But what seems not still very clear is that when you create a pointer the compiler doesn't automagically create also a variable to point to...
In code:
int *p;
int *q;
*p =10;
*q =10;
You are defining p and q as pointers to int, but to which variables of type int they point? They have a garbage inside and can point anywhere, so when assigning 10 to what they point to, in reality, you are spamming somewhere in memory.
Under these conditions when you call sum I would expect more a memory fault than a strange value (255), but everything can happen with bad pointers, even to access an existing memory.
The correct code is:
int sum(int *a , int *b);
int main()
{
int i1, i2; //Allocate 2 int variables
int *p = &i1; //Create pointers and assign them
int *q = &i2; //the address of int vars i1 and i2
*p =10; //Initialize variables pointed by pointers with 10
*q =10;
int c = sum(p,q);
printf("%d",c);
}
int sum(int *a , int *b)
{
return((*a)+ (*b));
}
A pointer needs to be assign the address of some valid memory to point to before it may be dereferenced of the *-operator and gets written some data to where it points to.
You miss those very assignments.
Dereferencing a pointer implies reading out its value. If no value ever had been assigned to a pointer variable, already reading out its value might invoke the infamous Undefined Behaviour, anything can happen after this.
So your result could also have been just the famous 42.
Lesson learned: Never apply any operator to a variable which had not been properly been initialised.
Another approach. I think it may be useless for return function but it can help you about pointers It is passing pointer to the sum function
#include <stdio.h>
int sum(int *a , int *b);
int main()
{
int p = 10;
int q = 10;
int c = sum(&p,&q);
printf("%d",c);
}
int sum(int *a , int *b)
{
return((*a)+ (*b));
}
You're getting 255 is because of random luck. I get 20 when I compile it, but that's also random luck. The technical term is "undefined behavior", and this is undefined because you never initialized your int *p and int *q pointers.
What's inside your pointer variables? You don't know, I don't know, nobody does. Since you never initialized them, their contents are whatever bits were there before initialization. It's like moving into a house and getting whatever junk the previous tenants left for you.
If the contents of the pointers are addresses in memory (and they don't overlap), then the value returned should be 20 (by random luck). But if one of them contains a null address, who knows what you'll get!
If you want to get 20 reliably, you need to allocate memory:
In C++:
int * p = new int;
int * q = new int;
In C:
int * p = (int*)malloc(sizeof(int))
int * q = (int*)malloc(sizeof(int))
This is my code, which allocates space for a matrix of size specified by the parameters, and returns a pointer to said matrix:
int **allocateSpace(int row, int col){
int i;
int **a;
a = malloc(sizeof(int *) * row);
for(i = 0; i < row; i ++)
a[i] = malloc(sizeof(int) * col);
return a;
}
The above code works as intended.
However, when I change the code to the following form I get a segmentation fault:
void allocateSpace(int **a, int row, int col){
int i;
a = malloc(sizeof(int *) * row);
for(i = 0; i < row; i ++)
a[i] = malloc(sizeof(int) * col);
}
It seems like when returning from the allocateSpace() function, the memory allocated was released (since I got a segmentation fault). But why? All I am doing is allocating memory for a given pointer, and it's all done in the subfunction.
To summarize my question: Why am I getting a segmentation fault in the second piece of code?
Thank you very much!
Because you need to pass in a pointer to a pointer to a pointer in order to assign the allocated memory:
void allocateSpace(int ***a, int row, int col){
int i;
*a = malloc(sizeof(int *) * row);
for(i = 0; i < row; i ++)
( *a )[i] = malloc(sizeof(int) * col);
}
And to call it you would need to pass the address of an int**:
int** ppData;
allocateSpace( &ppData, 10, 10 );
The problem is that you are trying to change a pointer that is passed by value:
void allocateSpace(int **a, int row, int col){
// ...
}
int** a here is passed by value (i.e. the pointer value is copied to the stack in order to use it as function parameter).
When you then do
a = malloc(sizeof(int *) * row);
you change only the copy of the pointer and once the function returns, your change is discarded.
The solution is to pass the pointer by reference, i.e.
void allocateSpace(int ***a, int row, int col){
//...
}
and change the real value by following the reference:
*a = malloc(sizeof(int *) * row);
In the second case you are modifying the function's parameter a - that is a local copy passed by value. So, if you call the function like: allocateSpace(myptr,N,M), myptr will not be modifed - a copy local to the function will. Therefore, myptr contains whatever it contained before the call - possibly garbage. You would need to change the function param to: int ***a (oh the horror) and then put an additional * (dereference op) before each reference to a in the function body.
Compare this to the situation where you want to modify a simple int in a function - the param should be int * and assignments in function body should go to *a. Same applies here - one additional level of dereference is needed to achieve your goal.
In the second function int **a is passed by value (the pointer) so changes in the function dont affect the caller's function. You have to pass this value by reference.
I'm trying to write a little matrix program. Using doublke pointers doesnt work so I figure the easiest way is to have a struct that has the #rows and #columns and a 1d array as the matrix.
But there is some error in the initiation of the matrix as i get:
weird values for the indices (0,0) and (0.1) instead of 0.
Something with this perhaps:
matrix *mtrx = malloc(sizeof(matrix));
mtrx->m = malloc(r * c * sizeof(int));
matrix.c:
#include <stdio.h>
#include <stdlib.h>
#include "Matrix.h"
matrix *alloc_matrix(int r, int c)
{
matrix *mtrx = malloc(sizeof(matrix));
mtrx->m = malloc(r * c * sizeof(int));
if (mtrx == NULL || m == NULL) {
printf("Out of memory.");
exit(1);
}
mtrx->rows = r;
mtrx->columns = c;
return mtrx;
}
void free_matrix(matrix *mtrx)
{
free(mtrx->m);
free(mtrx);
}
void set(matrix *mtrx, int r, int c, int v)
{
(mtrx->m)[r * mtrx->columns + c] = v;
}
int get(matrix *mtrx, int r, int c)
{
return (mtrx->m)[r * mtrx->columns + c];
}
void print_matrix(matrix *mtrx)
{
int i,j;
printf("\n");
for(i=0; i<mtrx->rows; i++) {
for(j=0; j<mtrx->columns; j++) {
printf("%i ", get(mtrx,i,j));
}
printf("\n");
}
}
matrix.h:
struct matrix_ {
int rows;
int columns;
int *m;
};
typedef struct matrix_ matrix;
matrix *alloc_matrix(int r, int c);
void free_matrix(matrix *mtrx);
void set(matrix *mtrx, int r, int c, int v);
int get(matrix *mtrx, int r, int c);
void print_matrix(matrix *m);
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "Matrix.h"
int main(void)
{
matrix *m = alloc_matrix(3,4);
print_matrix(m);
printf("\nm[0][0] = %i", get(m,0,0));
set(m,0,0,0);
printf("\nm[0][0] = %i", (m->m)[0]);
printf("\nm[0][0] = %i", (m->m)[12]);
return 0;
}
output:
all elements except (0,0) and (0,1) is 0.
Function malloc allocates a block of memory, returning a pointer to the beginning of the block. It doesn't set all its bits to zero.
Allocating a block of memory and initializing all its bits to zero - that's what calloc function is for.
Or you can explicitly set these bits to zero by using memset
The object allocated by malloc has an unspecified value. If needed, you have to zero-ize the object yourself (for example using memset function) or call calloc instead of malloc.
malloc() is not guaranteed to zero the memory. Use calloc() to allocate memory with zeros.
malloc does not initiate with 0's (because of performance issues... it's not always what you want)...
use calloc() instead.
malloc does not zero out allocated memory. If you want to fill the matrix with zeros on allocation, use calloc instead. In your case, replace:
mtrx->m = malloc(r * c * sizeof(int));
with
mtrx->m = calloc(r*c, sizeof(int));
Answering your follow-up question:
However is there any difference in efficiency between malloc+memset and calloc? or is calloc simplye malloc+memset?
Typically, for "small" allocations calloc is equivalent to malloc + memset. For "large" allocations (multiple pages, at least), your library may do something more clever relying on some amount of OS support. One approach would be for the OS to lazily zero fill the allocated pages as they are actually used, rather than zero filling all of them immediately upon allocation.
That is correct. The C specification does not say arrays are initilized to anything. You just get a piece of memory that will have whatever values there where before.
You can easily initialize to sero though: memset(mtrx->m, 0, sizeof(int) * r * c);