I was asked to write a program that produces a 2d array of random numbers. My code produces strange results. Regardless of the size of the matrix it produces a "reverse diagonal matrix" (not sure what else to call it). I was to understand that rand() produces a pseudorandom number between 0 and RAND_MAX but somehow the results are dependent on the size of my matrix, I am unsure how this behavior could happen.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAT_SIZE 5
void main (void)
{
srand(time(0));
unsigned char * ptr = malloc(MAT_SIZE*MAT_SIZE);
unsigned char i, j;
for(i = 0; i < MAT_SIZE; i++)
{
for(j = 0; j < MAT_SIZE ; j ++)
{
*(ptr + i + j ) = rand();
}
}
for(i = 0; i < MAT_SIZE ; i++)
{
for(j = 0; j < MAT_SIZE ; j ++)
{
printf("%5d", *(ptr + i + j));
}
printf("\n");
}
free(ptr);
}
Output for 3*3
142 141 11
141 11 230
11 230 28
Output for 5*5
232 157 62 131 245
157 62 131 245 54
62 131 245 54 138
131 245 54 138 246
245 54 138 246 108
Even a pseudorandom number shouldn't behave differently based on how it is used. Is there something I'm not understanding about the program that forces these results?
The problem is not with the random numbers that are generated but with how you are saving them in your matrix. To access element (j, i) you do not want
*(ptr + i + j )
but
*(ptr + MAT_SIZE * i + j )
You are only accessing the first i+j members of the array, and looping over the same indices repeatedly. Instead of:
*(ptr + i + j )
Try
*(ptr + i * MAT_SIZE + j )
Note that you can dynamically allocate a 2D array as follows:
unsigned char (*ptr)[MAT_SIZE] = malloc( MAT_SIZE * sizeof *ptr );
...
ptr[i][j] = rand();
...
free( ptr );
Makes life a little simpler. This way you can use normal 2D array indexing instead of having to map i and j to a single dimension.
Nits:
Unless your compiler documentation explicitly lists void main() as a valid signature for main, use int main( void ) instead. I know you've seen thousands of examples of void main() in books and on line, but just because the compiler doesn't complain about it doesn't mean it isn't wrong.
rand() returns int, which will not fit into an unsigned char. Overflow on unsigned types is well-defined, but even so, you may want to explicitly map your rand result onto the range [0..255].
Related
I tried creating function that dynamically allocates memory for 2 dimensional array and put some integer values into the array. Overall, the function worked as expected but there were some error. So I did the same thing within main() and got the right result. My code is like below:
#include <stdlib.h>
#include <stdio.h>
void test(int d1, int d2, int ***p){
int value;
*p = (int **)(malloc(sizeof(int)*d1));
for (int i = 0; i < d1; i++){
(*p)[i] = (int *)(malloc(sizeof(int)*d2));
for (int j = 0; j < d2; j++){
(*p)[i][j] = i * 10 + j;
}
}
printf("\n");
}
int main(void){
int d1, d2;
int ** ptr;
printf("length of 1st dimension?\n");
scanf("%d", &d1);
printf("length of 2nd dimension?\n");
scanf("%d", &d2);
test(d1, d2, &ptr);
for (int i=0; i<d1; i++){
for (int j=0; j<d2; j++){
printf("%d ", ptr[i][j]);
}
printf("\n");
}
free(ptr);
ptr = (int **)(malloc(sizeof(int)*d1));
for (int i=0; i< d1; i++){
ptr[i] = (int *)(malloc(sizeof(int)*d2));
for (int j=0; j<d2; j++){
ptr[i][j] = i *10 +j;
}
}
printf("\n######################\n\n");
for (int i=0;i<d1;i++){
for (int j=0; j<d2;j++){
printf("%d ", ptr[i][j]);
}
printf("\n");
}
free(ptr);
return 0;
}`
When I passed 5 as a length of 1st and 2nd dimension, I got the result like below:
length of 1st dimension?
5
length of 2nd dimension?
5
532699424 32725 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
######################
0 1 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
I think, except that I passed pointer to pointer to pointer as an argument to the function, I did the same thing. However some values in the first row are different. And I got different value for the first row whenever I executed the function.
Could someone please let me know what I did wrong?
Thank you in advance.
The lines
*p = (int **)(malloc(sizeof(int)*d1));
ptr = (int **)(malloc(sizeof(int)*d1));
are wrong. The elements is int*, but only room for int is allocated per element.
This may cause trouble if int* is larger than int (for example, when int* is 8 bytes and int is 4 bytes).
The lines should be
*p = malloc(sizeof(int*)*d1);
ptr = malloc(sizeof(int*)*d1);
or (with risk of making mistake reduced by avoiding writing type manually)
*p = malloc(sizeof(*p)*d1);
ptr = malloc(sizeof(*ptr)*d1);
See also: c - Do I cast the result of malloc? - Stack Overflow
I'm working on a homework problem for C and unix programming, and the teacher told us to write a sort function for an array in C.
I've got sorting working from some for loops in main, but the separate sort function we need doesn't work.
#include <stdio.h>
#include <stdlib.h>
int Sort(int arr[], int size){
int i,j,a;
for(i = 0; i < size; i++){
for(j = i+1; j < size; j++){
if(arr[i] > arr[j]){
a = arr[i];
arr[i] = arr[j];
arr[j] = a;
}
}
return arr;
}
}
int main(){
int a;
int BAT[40];
for(int i=0; i < 40; i++){
BAT[i] = (float)(599)* ( (float)rand() / (float)RAND_MAX );
printf("%d \n", BAT[i]);
}
printf(" the array should now be sorted \n");
//Sort(BAT, 40); THIS IS THE FUNCTION CALL THAT DIDNT SEEM TO WORK SO I COPIED THE SORT OUT OF THE SORT FUNCTION TO TEST
//THIS IS THE SORT CODE AND WHILE IT IS IN THE MAIN IT WORKS
for(int i = 0; i < 40; i++){
for(int j = i+1; j < 40; j++){
if(BAT[i] > BAT[j]){
a = BAT[i];
BAT[i] = BAT[j];
BAT[j] = a;
}
}
}
//END OF SORTING TEST
for(int j=0; j < 40; j++){
printf("%d \n", BAT[j]);
}
I expect the Sort(BAT, 40) to sort the array which I then try to print but instead nothing seems to occur.
Your sort routine should have worked as written, but you are failing to enable warnings in your code and thus you are not allowing the compiler to help you fix the warnings and errors in your code -- that alone would have allowed your code to run just fine.
For instance, your compiler will tell you the exact line number, and many times the exact character in that line where the error or warning was detected, e.g.
bubblesortfn.c: In function ‘Sort’:
bubblesortfn.c:21:5: warning: return makes integer from pointer without a cast
[enabled by default]
return arr;
^
How can a return make an integer from a pointer?? Simple, you have your function attempting to return an integer array (int *), and you have your function declared int Sort. (you don't need to return anything, but you can simply fix it by changing your declaration to int *Sort (....)).
The remainder of the problems are simple syntax issues and unused variables (e.g. a in main()) that would be instantly flagged by your compiler -- listen to it. Let it help you write better code.
Always compile with warnings enabled, and do not accept code until it compiles cleanly without warning. To enable warnings add -Wall -Wextra -pedantic to your gcc/clang compile string. For clang, instead you can use -Weverything. For VS (cl.exe on windows), use /W3 (or use /Wall but you will get quite a few extraneous non-code related warnings). Read and understand each warning -- then go fix it.
As mentioned in my comment, don't use magic numbers in your code (except where absolutely required like with the fscanf field-width modifier). Instead, If you need a constant, #define one (or more), or use a global enum to do the same thing. That way you have one single place at the top of your code to change things if needed and you don't have to go picking through your declarations or loop limits to change things.
Literally, fixing the warnings identified and tidying things up a bit was all that was needed to get your code working and properly sorting the array in your Sort function (I also added a prnintarray() function to print your array to avoid the repeated loops in main(). Putting it altogether, and seeding the random number generator by calling srand() before you use rand(), you could do:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* if you need a constant, define one (or more) - avoid magic numbers */
#define ROWSZ 10 /* max integers to print per-row */
#define MAXB 40 /* max integers in BAT */
#define MULTP 599 /* multiplier constant */
int *Sort (int arr[], int size)
{
int i, j, a;
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++) {
if (arr[i] > arr[j]){
a = arr[i];
arr[i] = arr[j];
arr[j] = a;
}
}
}
return arr;
}
/* simple print function to output arr of sz with rowsz int per-row */
void prnintarray (int *arr, size_t sz, size_t rowsz)
{
for (size_t i = 0; i < sz; i++) {
if (i && i % rowsz == 0)
putchar ('\n');
printf (" %4d", arr[i]);
}
putchar ('\n');
}
int main (void) {
int BAT[MAXB] = {0}; /* initialize all arrays - good practice */
srand (time(NULL)); /* seed the random number generator */
for (int i = 0; i < MAXB; i++) /* fill array */
BAT[i] = MULTP * ( (float)rand() / (float)RAND_MAX );
puts ("\nunsorted array:\n");
prnintarray (BAT, MAXB, ROWSZ);
Sort (BAT, MAXB);
puts ("\nsorted array:\n");
prnintarray (BAT, MAXB, ROWSZ);
}
Example Use/OUtput
$ ./bin/bubblesortfn
unsorted array:
461 519 346 508 265 93 358 407 278 151
465 531 430 148 181 227 452 206 401 202
103 518 259 267 342 495 570 431 477 455
164 339 375 511 248 42 6 8 450 284
sorted array:
6 8 42 93 103 148 151 164 181 202
206 227 248 259 265 267 278 284 339 342
346 358 375 401 407 430 431 450 452 455
461 465 477 495 508 511 518 519 531 570
Look things over and let me know if you have further questions.
Use qsort For Real-World Sorting
While there is nothing wrong with writing a bubblesort function for the learning aspect of it, the C-library provides qsort which can, and should, cover the majority of your sorting needs. Your only job in using qsort is to write a simple compare() function to tell qsort how to sort adjacent members of the array. The prototype for the compare() function usually sends new C programmers into a state of panic. The prototype is:
int compare (const void *a, const void *b)
Don't let it bother you. a and b are just pointers to the two members of your array currently being compared. Your job is to write the remainder of the function so that if the value pointed to by a:
sorts before the value pointed to by b, a negative number is returned;
is equal to the value pointed to by b, zero is returned and finally
sorts after b a positive values is returned. (all just like strcmp).
To handle the fact that a and b are void pointers, you simply cast them to int pointers before dereferencing to make use of their values, e.g.
int compare (const void *a, const void *b)
{
const int *pa = a, /* a and b are pointers to elements being compared*/
*pb = b; /* in array, cast as required to proper type */
Since your array is int, a and b will be pointers-to int, you simply cast them to int *. Now you can access the values through the pointers (e.g. dereference *pa to get the value at the address held by pa).
Now to satisfy the return requirements the trivial solution would be:
return *pa - *pb;
However, if the *pa is a large negative value and *pb is a large positive value, subtracting *pa - *pb can easily result in integer overflow and undefined behavior. Instead of a direct subtraction, by using two inequalities, chance of overflow can be eliminated while providing the needed return. Think through:
return (*pa > *pb) - (*pa < *pb);
So putting your qsort function together and replacing your call to Sort with a call to qsort, you would rewrite your code as:
int compare (const void *a, const void *b)
{
const int *pa = a, /* a and b are pointers to elements being compared */
*pb = b; /* in array, cast as required to proper type */
/* inequality avoids overflow from subtracting 2 large values
* (x > y) - (x < y) , returns -1, 0, 1 (like strcmp) for
* -1 -> x sorts before y, 0 -> x equals y, 1 -> x sorts after y
*/
return (*pa > *pb) - (*pa < *pb);
}
Then
qsort (BAT, MAXB, sizeof *BAT, compare);
Give it a try. As a bonus for large arrays, qsort will be Orders of Magnitude faster than a bubblesort (one of the slowest sorts for large arrays)
It might be a stupid question, but I wonder if there is a efficient way to do this.
The situation:
int* array = malloc(n * m * sizeof(int));
//want to convert array into M[n][m]
what I am doing now:
int** M = malloc(n * sizeof(int*));
for(int i = 0; i < n; i++, array += m)
M[i] = array;
I don't think the conversion should be this complex. Is there any simple syntax C provided? Can I declare an extern M[n][m] then set its address to the array?
(error handling and memory management in the sample is omitted for simplicity. Just think it as a part of some function.)
After:
int* array = malloc(n * m * sizeof(int));
you can do:
int (*M)[m] = (int(*)[m])array;
and then use M[1][2] for example.
You could have done that in the first place too :
int (*M)[m] = malloc( n * sizeof *M );
The tricky part is declaring the variable to hold the pointer to the allocated array; the rest is straight-forward — assuming you have a C99 or later compiler.
#include <stdio.h>
#include <stdlib.h>
static void print_2dvla(int rows, int cols, int data[rows][cols])
{
for (int i = 0; i < rows; i++)
{
printf("%2d: ", i);
for (int j = 0; j < cols; j++)
printf(" %4d", data[i][j]);
putchar('\n');
}
}
int main(void)
{
int m = 10;
int n = 12;
int (*M)[m] = malloc(n * m * sizeof(M[0][0]));
if (M == NULL)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", n * m * sizeof(M[0][0]));
exit(EXIT_FAILURE);
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
M[i][j] = (i + 1) * 100 + (j + 1);
}
print_2dvla(n, m, M);
free(M);
return 0;
}
Example output:
0: 101 102 103 104 105 106 107 108 109 110
1: 201 202 203 204 205 206 207 208 209 210
2: 301 302 303 304 305 306 307 308 309 310
3: 401 402 403 404 405 406 407 408 409 410
4: 501 502 503 504 505 506 507 508 509 510
5: 601 602 603 604 605 606 607 608 609 610
6: 701 702 703 704 705 706 707 708 709 710
7: 801 802 803 804 805 806 807 808 809 810
8: 901 902 903 904 905 906 907 908 909 910
9: 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
10: 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
11: 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
The key line is:
int (*M)[m] = malloc(n * m * sizeof(M[0][0]));
This says that M is a pointer to an array of int arrays each of which has the dimension m. The rest of the code simply uses that array with the usual 2-subscript notation — M[i][j] etc. It can be passed to functions. I've not shown it here, but it is trivial to put the initialization code into a function too, and then have several different sizes of matrix in a single function.
You can't declare global arrays in C without giving them a specific numerical size. This is because global variables are static and the compiler can't allocate a variable amount of memory for a global array.
In C you've got to remember that an array is actually just a pointer. When you're asking for int *array = malloc(n * sizeof(int)) what you're telling the compiler is that you need n lots of 4 byte blocks of int type reserved side by side in memory, where the value of array is actually a pointer to the first 4 byte block.
When you are accessing elements of an array you are actually doing pointer arithmetic and dereferencing the pointer, but this is hidden in the array[i] syntax. So, when array has int type, array[2] translates as go to the location given by the array pointer (i.e. the head) now move 2 * 4 bytes along in memory and dereference the pointer to access the integer stored there.
So when you're creating a 2-d array as you've discussed, there really isn't a better way of doing it. Make sure you have a firm grip on what it actually is you're getting from the compiler. Pointers are (on 64-bit machines anyway) 8 bytes and ints are 4 bytes. So when you call int **M = malloc(sizeof(int*) * m the compiler allocates you m blocks of width 8 bytes each, all of which have type int*.
From other programming languages it seems very over the top having to declare a pointer reference to a block of pointers, but getting passed the higher level idea of an array and considering them as a collection of pointers will really help you in the long run. When you need to pass these data types between functions you need to be able to have a firm idea of what you are actually manipulating; a pointer, a value, a pointer to a pointer? It will help you a lot in debugging code these ideas, as it is very easy to try and perform computations on pointers rather than values.
3 Useful Tips:
calloc(n, sizeof(int)) might be a better fit than calling malloc because calloc automatically initialises your entries to zero whereas malloc doesn't.
when calling calloc/malloc, you want to check that your dynamic memory allocation has been successful; if it isn't successful, then malloc will return NULL.
A good rule of thumb is that every time you call malloc you want to call free once you're done with the memory. This can help to prevent memory leaks.
Use an array of pointers.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n = 3, m = 4, i, j, count=0;
int *array[n];
for(i=0; i<n; i++)
array[i] = (int *)malloc(m * sizeof(int));
if( array[i] == NULL)
{
perror("Unable to allocate array");
exit(1);
}
// going to add number to your 2d array.
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
array[i][j] = ++count;
for (i=0; i < n; i++)
for (j=0; j < m; j++)
printf("%d ", array[i][j]);
// free memory
for(i=0; i<n; i++)
free(array[i]);
}
Why is the data preserved for the second call when I haven't used static?
Here is the code, the output and what I've expected the output should be.
#include <stdio.h>
void fun(int len)
{
int arr[10];
int i;
for (i = 0; i < len; i++)
arr[i] = (i+1) * 10;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main(void) {
fun(10);
fun(4);
return 0;
}
output:
10 20 30 40 50 60 70 80 90 100
10 20 30 40 50 60 70 80 90 100
expected output:
10 20 30 40 50 60 70 80 90 100
10 20 30 40 0 0 0 0 0 0
int arr[10]; declares an array of 10 int elements on the stack. Its elements are uninitialized. If you attempt to access them without initialization, as is the case with fun(4), you may see garbage values, you may happen to see old memory contents (as you did here), or you may crash the program with a segmentation fault if the memory page belongs to another program. You may even get your expected output! In fact, anything can happen because behavior is undefined by the specification.
To meet your expectations, initialize the array in any way you choose, such as one of the following:
int arr[10] = {};
int arr[10] = {0};
int arr[10];
memset(arr, 0, sizeof(int) * 10);
int arr[10];
for (int i = 0; i < 10; i++) {
arr[i] = 0;
}
etc.
Please initialize array.
Like this
void fun(int len)
{
int arr[10] = {0}; //changed
int i;
for (i = 0; i < len; i++)
arr[i] = (i+1) * 10;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);
printf("\n");
}
You are invoking undefined behavior by accessing uninitialized memory. The result could be literally anything, including your computer growing legs and running away.
In practice, what is probably happening is that your function calls occupy the same place on the stack since there are no other calls between or within them. The arr variable ends up on the same spot on the stack both times. The first initialization is more comprehensive than the second, so you don't see total garbage. This is to be expected, but certainly never relied upon.
array arr[] is allocated in stack which is uninitialized by default, the values are the ones used last time this area was allocated, in this it happens to allocate the same stack area between the 2 fun calls, and the stack area was initialized by the first call.
I was playing around with pointers when inputing a matrix with scanf and for some reason, when I run this code, only the first element of every row gets stored correctly.
#include "stdio.h"
void main()
{
int i, j, n, A[10][10];
scanf("%d", &n);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
scanf("%d", A + j + i*10);
}
This is what I get after inputing 1,2,3,4,5,6,7,9 into a 3x3 matrix and printing it:
1 -858993460 -858993460
2 -858993460 -858993460
3 -858993460 -858993460
According to my understanding of how matrices are stored, this should work. Can anyone point out whats wrong with my code?
You declare A as
int A[10][10];
that is, an array of 10 arrays of 10 ints each. Thus, when A decays to a pointer to its first element, the type of that pointer is int (*)[10]. That's a pointer to an array of 10 ints, not a pointer to a single int. Among the differences is their interaction with pointer arithmetic. Because pointer arithmetic is defined in terms of the size of the pointed-to type, whenever i is nonzero, the expression A + j + i*10 produces a pointer (to array of 10 ints) outside the bounds of array A.
The most type-safe way of doing what you want would be to use array syntax to select array elements:
&A[i][j]
. Type-correct alternatives that use pointer arithmetic include
&(*(A + i))[j]
and
*(A + i) + j
These latter two both rely on the fact that the expression A + i is a pointer to an array of int; dereferencing that pointer produces an array, which can be the operand of the [] operator (and the address of the result then taken). Alternatively, the array designated by *(A + i) decays to a pointer to its first element (i.e. decays to an int *) when it appears as an operand of the + operator, and adding j to that yields a pointer to the jth element of array *(A + i) (which is the same array designated by A[i]).
Bad pointer math.
A + j + i * 10
When A is used in A + j + i*10, it becomes the pointer to its first element, which is an array of 10 int. Every 1 added to A offsets its address by 40 bytes.
Recommend to use &A[i][j] instead.
Code re-worked to show addresses used.
#include "stdio.h"
int main() {
int i, j, n, A[10][10];
n = 3;
char *base = (char*) A;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
char *offset0 = (char*) (&A[i][j]);
char *offset1 = (char *) (A + j + i * 10);
printf("%d %d %3td %3td\n", i, j, offset0 - base, offset1 - base);
}
}
Output
0 0 0 0
0 1 4 40
0 2 8 80
1 0 40 400
1 1 44 440
1 2 48 480
2 0 80 800
2 1 84 840
2 2 88 880