Unexpected outputs, why? - c

This is simple, I am allocating a dynamic 2d array using functions. I limited the scanf() len and my problem is when input a value over the limit, something weird happen.
Example
Input: 111,222,333,444
Expected output: 11,22,33,44
Real output: 11,12,33,34
#include <stdio.h>
#include <stdlib.h>
#define gd 2
void get_mem(int ***arr);
void get_data(int **arr);
int main(){
int **arr;
arr = NULL;
get_mem(&arr);
get_data(arr);
free(*arr);
return 0;
}
void get_mem(int ***arr){
int i;
*arr = (int**)malloc(gd*sizeof(int*));
for(i=0;i<5;i++){
(*arr)[i] = (int*)malloc(gd*sizeof(int));
}
printf("oki\n");
}
void get_data(int **arr){
int c,f;
for(c=0;c<gd;c++){
for(f=0;f<gd;f++){
scanf("%2d",&*(*arr+c)+f);
fpurge(stdin);
fflush(stdin);
}
}
for(c=0;c<gd;c++){
for(f=0;f<gd;f++){
printf("%d ",*(*arr+c)+f);
printf("\n");
}
}
}

The value of macro gd is 2. In get_mem(), allocating memory for 2 int *:
*arr = (int**)malloc(gd*sizeof(int*));
and below it, accessing arr beyond it size:
for(i=0;i<5;i++){ //allocating memory to 5 int pointers
^^
(*arr)[i] = (int*)malloc(gd*sizeof(int));
}
Accessing an unallocated memory is undefined behaviour.
Instead of using magic number 5 in the loop condition, you should check i with gd, like this
for(i=0;i<gd;i++){
In get_data(), the way you are accessing elements of arr for input is wrong
scanf("%2d",&*(*arr+c)+f);
^^^^^^^^^^^^
because
&arr[c][f] --> &(*(arr[c] + f) --> &(*(*(arr + c) + f)) --> &*(*(arr + c) + f) --> (*(arr + c) + f)
Note: The operator & is used to get the address and the operator * is used for dereferencing. These operators cancel the effect of each other when used one after another. Hence, &(*(arr + i)) is equivalent to arr + i.
That means, &arr[c][f] is equivalent to (*(arr + c) + f) and you should use &arr[c][f] which is less error prone and more readable:
for(f = 0; f < gd; f++) {
scanf("%2d", &arr[c][f]);
Same mistake you have made while printing the arr elements in second for loop:
for(f=0;f<gd;f++){
printf("%d ",*(*arr+c)+f);
^^^^^^^^^^^
It should be *(*(arr + c) + f). More readable form is arr[c][f]:
for(f = 0; f < gd; f++){
printf("%d ", arr[c][f]);
You should not use fflush() for input stream. It's undefined behavior. From C Standards#7.21.5.2p2 -
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
Also, fpurge() is nonstandard and not portable. Moreover, you don't need to use either of them.

Rather than using more & more pointers, I'd like to do it in this way:-
#include <stdio.h>
#include <stdlib.h>
//#define gd 2
#define ROW 2
#define COLUMN 2
void get_mem(int ***arr);
void get_data(int **arr);
int main(){
int **arr = NULL;
get_mem(&arr);
printf("Enter 4 int values: ");
get_data(arr);
free(*arr);
return 0;
}
void get_mem(int ***arr)
{
int i;
*arr = ( int ** )malloc( ROW * sizeof(int *) );
for(i = 0; i < COLUMN; i++)
{
(*arr)[i] = ( int * )malloc( COLUMN * sizeof(int) );
}
printf("Okay!\n");
}
void get_data(int **arr)
{
int c, f;
for(c = 0; c < ROW; c++)
{
for(f = 0; f < COLUMN; f++)
{
scanf("%2d", &arr[c][f]); //*(*arr+c)+f)
}
}
for(c = 0; c < ROW; c++)
{
for(f = 0; f < COLUMN; f++)
{
printf("%d ", arr[c][f]); //*(*arr+c)+f)
}
putchar('\n');
}
}
I don't know what that gd is but it was making code ambiguous so I removed that and replaced it with ROW & COLUMN everywhere in the program(where it was necessary).
After allocating space to int **arr via get_mem() function, at least ask the user to input values and use proper spacing & indenting.
There's no need of fflush or fpurge, so I removed them.
Now, here if you're accessing array this way you need to be very careful of using parenthesis at proper places. You should use *(*(arr+c)+f) instead of *(*arr+c)+f)(It was an error.) this. But I chose to access the elements or store values as we do in 2D arrays. That's easier.
If you want to access this array using pointers only, instead of arr[c][f] you can do it in this way:-
scanf("%2d", &(*(*(arr+c)+f)));
&
printf("%d ", *(*(arr+c)+f));
Note: Also, you should check for any error while allocating memory.
Hope, it helps.

Related

Function passing of multidimensional array in c

#include <stdio.h>
void spiral(int a[10][10]) {
printf("%d", a[1][3]);
}
int main() {
int r, c, j, i;
scanf("%d%d", &r, &c);
int a[r][c];
for (i = 0; i < r; i++)
for (j = 0; j < c; j++) {
scanf("%d", &a[i][j]);
}
spiral(a);
return 0;
}
When I give a 3 x 6 array
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
The output is 14, while it should be 10
How to fix this issue?
If you enter 3 and 6 for r and c (respectively) then the type of a is not int[10][10] (or int(*)[10] as the spiral argument really is), it's int[3][6]. The memory layout is completely different for the arrays, leading to undefined behavior.
You can solve this by passing the size along to the function, and using it in the declaration of the array:
void spiral(const size_t r, const size_t c, int (*a)[c]) { ... }
Call it like expected:
spiral(r, c, a);
As noted using int a[r][c] as argument might be easier to read and understand, but it gives a false impression that a is actually an array. It's not. The compiler treats the argument as a pointer to an array of c integers, i.e. int (*a)[c].
This makes me a little conflicted... On the one hand I'm all for making things easier to read and understand (which means it will be easier to maintain), on the other hand newbies often get it wrong and think that one can pass an array intact when in fact it decays to a pointer which can lead to misunderstandings.
A few things are wrong: in void spiral() you ask for a 2D-array of 10*10, but you do not give that. Keep that part as a variable, so only ask the type you receive and not what you want to receive and with creating a dynamic array you should always do that with malloc or calloc and free them afterwards. This might be a bit hard at first, but when you start creating bigger programs this is a must if you have a question or do not understand the pointers in the program called (*) then ask me:
#include <stdio.h>
#include <stdlib.h>
void spiral(int **a) {
printf("%d", a[1][3]);
}
int main() {
int r, c, j, i;
scanf("%d%d", &r, &c);
int **a = malloc(r * sizeof(int*));
for (i = 0; i < r; i++) {
a[i] = malloc(c * sizeof(int));
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
scanf("%d", &a[i][j]);
}
}
spiral(a);
for (i = 0; i < r; i++) {
free(a[i]);
}
free(a);
return 0;
}

How can I store these numbers in C?

Lets say you had an array like this
{ 1 2 5 7 2 3 7 4 2 1 }
And you wanted to store that the difference between the first half of the array and the second half is at positions 2 and 4.
The trick is, I need to use those stored numbers later in other code, so what I can't figure out is how I would store these numbers.
I have this method
int * getPositions(int *array, int size){
int * c[(size/2)];
int counter = 0;
for(int i = 0; i < size /2; i++) {
if (*(array + i) != *(array + (size - 1) - i)) {
c[counter]= (int *) i;
counter++;
}
}return (int *) c;
}
but it seems to be storing -1774298560 into every location. I know that cause when I try to print it
int c = (int) getPositions(array, size_of_array);
for(int i = 0; i < ((size_of_array/2)); i++){
printf("%d\t", c);
}
all it prints out is
-1774298560 -1774298560 -1774298560 -1774298560 -1774298560
PS: I have array and size_of_array initialized somewhere else.
PS: I have taken the comments into consideration and changed the code to the following
int * getPositions(int *array, int size){
int * c = (int *) malloc((size_t) (size/2));
int counter = 0;
for(int i = 0; i < size /2; i++) {
if (*(array + i) != *(array + (size - 1) - i)) {
c[counter]= i;
counter++;
}
}
If the function should return a simple int array, you need to declare a pointer-to-int, and then call malloc to reserve space for the array. Then fill in the array, and return the pointer. The calling function will need to free the memory at some point.
int *getPositions(int *array, int size)
{
int *c = malloc( (size/2) * sizeof(int) );
if ( c == NULL )
return NULL;
// put stuff in the array using array syntax, e.g.
c[0] = array[0];
return c;
}
Call the function like this
int *c = getPositions( array, size );
if ( c != NULL )
for( int i = 0; i < (size/2)); i++ )
printf( "%d\t", c[i] );
free( c );
Notes:
Yes, error checking in C is a pain, but you must do it, or your
program will randomly crash.
You are allowed to use array syntax with a pointer, just be sure you don't read or write past the end of the memory that the pointer references.
It's legal to pass a NULL pointer to free.
Another option.
int * getPositions(int *array, int size);
int main() {
int array[] = { 1, 2, 5, 7, 2, 3, 7, 4, 2, 1 };
int size_of_array = sizeof(array) / sizeof(int);
int *ptr = getPositions(array, size_of_array);
for(int i = 0; ptr[i] != '\0' ; i++){
printf("%d\t", *(ptr + i));
}
return 0;
}
int * getPositions(int *array, int size) {
int temp[size/2];
int counter = 0;
for (int i = 0; i < size / 2 ; i++) {
if (array[i] != array[(size - 1) - i]) {
temp[counter++] = i;
}
}
int *c = malloc(counter * sizeof(int));
for (int i = 0; i < counter; i++) {
c[i] = temp[i];
}
return c;
}
My compiler going mad actually...which compiler you're using? Any modern static analyzer should have warned you
aftnix#dev:~⟫ gcc -std=c11 -Wall st.c
st.c: In function ‘getPositions’:
st.c:8:25: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
c[counter]= (int *) i;
^
st.c:11:6: warning: function returns address of local variable [-Wreturn-local-addr]
}return (int *) c;
^
st.c: In function ‘main’:
st.c:16:13: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
int c = (int) getPositions(array, 10);
So compiler is showing all the problems of the code. And your edited code doesn't even compile :
aftnix#dev:~⟫ gcc -std=c11 -Wall st.c
st.c:4:4: error: expected identifier or ‘(’ before ‘[’ token
int[] getPositions(int *array, int size){
^
st.c: In function ‘main’:
st.c:17:5: warning: implicit declaration of function ‘getPositions’ [-Wimplicit-function-declaration]
int c = (int) getPositions(array, 10);
Couple of things you have to take into consideration.
If you need to return a storage address, never try to return a local variable. As local variables are allocated in the Stack. Stack frames have the same lifetime of the function. Use malloc and co to allocate memory at the Heap. Understanding how the Runtime data structures are allocated and used is a very essential for a C programmer as C doesn't have fancy magical stuff under the hood. C is pretty much bare metal.
Stack Vs Heap
When passing arrays/pointers around, you should first think about your design first. Do you want to change your original array "in place"? or you want a different copy of "transformed" array. Usually you should try to avoid changing a memory "in place" as there might be other users to that. But if don't have such worries, you can then design your function as a "input->output" basis. That means you will not be returning void, and will return the transformed array itself.

qsort in C based on a column in 2d array: unexpected behavior

I am trying to sort a 2d array based on a particular column using qsort in C. I am attaching a minimal working code I am using. Essentially I am passing the pointer to the rows of the array to qsort, and based on the column number I want to sort, I modify the element to compare inside the compare function. Now, according to C convention, if I have 2 columns, I expect colnum=0 and colnum=1 to correspond to columns 1 and 2. But, in my implementation, I get the correct result if colnum=1 means column 1 and colnum=2 means column 2. I am stumped as to why this should be ? (I have also included the array allocation function I use).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "myfun.h"
static int colnum = 0;
int cmp(const void * a,const void * b);
int main(){
int i;
double **z1;
z1=matrix(5,2);
for (i=0; i<5; i++){
z1[i][1]=-i-1; z1[i][2]=16*i+10;
printf("before sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}
colnum=2;
qsort(z1,5,sizeof(double*),cmp);
for (i=0; i<5; i++){
printf("after sort z1 %lf %lf \n",z1[i][1],z1[i][2]);
}
getchar();
}
int cmp(const void * a,const void * b)
{
double** x = (double**) a;
double** y = (double**) b;
double xval, yval;
xval = *(*(x)+colnum);
yval = *(*(y)+colnum);
printf("%lf %lf \n",xval,yval);
if (xval < yval )
{
return 1;
}
else if (xval > yval)
{
return -1;
}
else
{
return 0;
}
}
double** matrix(int rows,int cols){
int k;
double **m;
m = (double **)malloc(rows * sizeof(double *));
for (k=0; k<rows; k++){
m[k] = (double *)malloc(cols * sizeof(double));
}
return m;
}
Your program has undefined behavior, because your are accessing memory beyond the boundary allocated by your inner allocation loop of matrix():
m = (double **) malloc(rows * sizeof(double *));
for (k = 0; k < rows; k++) {
m[k] = (double *) malloc(cols * sizeof(double));
}
Since cols has the value 2, malloc() only returns memory for 2 elements of type double. But, your code is initializing and reading a non-existing third element instead.
Since doing so is undefined, producing the output you expect is within the realm of possible behaviors. However, it is incorrect since you run the risk of corrupting the heap, and reading invalid data. Running your program under valgrind produces "Invalid write" and many "Invalid read" errors due to this problem in your program.
The correct approach is to store the values in their proper 0 and 1 column indexes in your initialization, set colnum to 1 to sort by the second column, and read from the proper 0 and 1 indexes when you print the array values.
z1 = matrix(5, 2);
for (i = 0; i < 5; i++) {
z1[i][0] = -i - 1;
z1[i][1] = 16 * i + 10;
printf("before sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
}
colnum = 1;
qsort(z1, 5, sizeof(double *), cmp);
for (i = 0; i < 5; i++) {
printf("after sort z1 %lf %lf \n", z1[i][0], z1[i][1]);
}
As a side note, when I was formatting your code for this answer, I noticed that you used an old C anachronism, probably unintentionally:
z1[i][1]=-i-1; /*...*/
The =- construct was the original C's (pre C.89) way of spelling the -= operator. It is highly unlikely you will end up using a compiler that will honor that operator without a diagnostic, but you should be wary of this syntax, and separate the = and the - tokens to remove the ambiguity.
z1[i][1] = -i - 1; /*...*/

malloc a char[][]

I am trying to malloc a char to have rows and columns with one letter in each cell. Something similar to int x[i][j] where I have i*rows and j*columns. Basically I want to make this:
|
1
222
33333
4444444
I tried with this code but it gives me an error: assignment makes an integer from pointer without a cast
A=(char**) malloc (5*sizeof(char*));
for(i=0;i<N+2;i++)`{
A[i]=(char*) malloc(7*sizeof(char));
}
for(i=0;i<3;i++){
for(j=0;j<7;j++){
left=3;
right=3;
if((j>=left)&&(j<=right)){
A[i][j]=i;
}
}
left--;
right++;
}
I would go with different approach:
#define STEPS 5
#define ARRAY_SIZE STEPS*STEPS
The size of the array in your case can be easily calculated by the formula above.
Now, you just need to allocate fixed size of bytes, and fill it. That's it. Even more, the version below will simply out-beat your version in simplicity and performance.
int i, j;
char *array;
array = malloc(ARRAY_SIZE);
for (i = 0; i < STEPS; i++)
for (j = 0; j < (i * 2 + 1); j++)
*(array + i * STEPS + j) = i + 1;
Proof.
This compiles fine for me, as long as I add this around your code snippet; note that "A" was declared as being of type "char **". It won't work if you write, say "char A[][]".
#include <stdlib.h>
int main() {
const int N = 10;
int i, j, left, right;
char **A;
/* your code */
return 0;
}

c pointer understanding issue

Please have a look at the following code and tell me where does ***ptr locates ?
i.e. i have a feelings that ***ptr actually locates at ptr[0][0][0]
Am I wrong ? The following is a 3d representation of pointer. where I am trying to assign some characters and later i wanted to test what is the index of ***ptr? will be waiting
#include<stdio.h>
#include<conio.h>
#define row 5
#define rw 3
#define col 10
char ***ptr;
int i,j,k;
void main()
{
clrscr();
ptr=(char *)malloc(row*sizeof(char *));
for(i=0;i<row;i++)
{
*(ptr+row)=(char *)malloc(rw*sizeof(char *));
printf("\t:\n");
for(j=0;j<rw;j++)
{
*(*(ptr+row)+rw)=(char *)malloc(col*sizeof(char *));
if(i==0 && j==0)
{ // *(*(ptr+row)+rw)="kabul";
**ptr="zzz";
}
else
*(*(ptr+row)+rw)="abul";
printf("\taddress=%d %d%d = %s\n",((ptr+row)+rw),i,j,*(*(ptr+row)+rw));
}
printf("\n");
}
printf("%c %d",***ptr,ptr);
getch();
}
First of all, I find your coding style extremely hard to read.
Answering your question, yes, ptr[0][0][0] is a synonym of ***ptr. Thats because a[b] is by definition equal to *(a+b), so ptr[0] is equal to *ptr, etc.
Said that, here is my version of your code:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define row 5
#define rw 3
#define col 10
char ***ptr;
int main()
{
int i, j;
ptr = (char***)malloc(row * sizeof(char **));
for(i = 0; i < row; i++)
{
ptr[i]= (char**)malloc(rw * sizeof(char *));
printf("\t:\n");
for(j = 0; j < rw; j++)
{
ptr[i][j] = (char*)malloc(col * sizeof(char));
if (i == 0 && j == 0)
{
strcpy(ptr[i][j], "zzz");
}
else
{
strcpy(ptr[i][j], "abul");
}
printf("\taddress=%p %d,%d = %s\n", ptr[i][j], i, j, ptr[i][j]);
}
printf("\n");
}
return;
}
Note the following changes:
Never write void main in C or C++. And throw away any book that prints it.
The argument of malloc is usually the number of elements times the size of the element. Place special attention to the real type that you intend to use.
The return of malloc is usually cast to the type pointer-to-the-type-of-the-element.
The index in the arrays should be i and j, not row and rw.
Why all the *(ptr + x) stuff? That's why we have the ptr[x] syntax.
You probably want to use strcpy to fill your strings, but difficult to say without explaining the problem.
When you want to printf a pointer, use %p.
If you use malloc, include <stdlib.h>.
Prefer local variables (i, j) to global ones, particularly for loops.
And a few other minor changes here and there...
PS. <conio.h>? Really? Are you still using Turbo-C or what?

Resources