Trying to script a matrix multiplication experiment - c

So I am tasked with scripting a program that multiplies random matrices between size 50 and 3000, and I have hit a snag. I am unsure of the best way to change the size while the script is running. I could manually do it but that would take hours of sitting in front of the computer, and I feel like there is a simple way that I am missing. I am aware that if I define these matrices within main, anything over about 800 will cause the proverbial stack overflow, which is why I have placed them outside of main. Unfortunately, now I cannot simply pass N as argv[1]. My question is this: is it possible to be able to script something along these lines:
./matrix 50
./matrix 150
./matrix 200
et cetera
and if so, how?
#include <foo>
#define N 1000
int A[N][N];
int B[N][N];
int result[N][N];
int main(int argc, char *argv[]){
//so on
thank you in advance to all who reply.

If the dimension n is passed to the program as an argument, the
malloc/calloc is a good option. I'd do something like this:
int **matrix_create(size_t dim)
{
int **matrix = calloc(dim, sizeof *matrix);
if(matrix == NULL)
return NULL;
for(size_t i = 0; i < dim; ++i)
{
matrix[i] = calloc(dim, sizeof *matrix[i]);
if(matrix[i] == NULL)
{
matrix_free(matrix, dim);
return NULL;
}
}
return matrix;
}
void matrix_free(int **matrix, size_t dim)
{
if(matrix == NULL)
return;
for(size_t i = 0; i < dim; ++i)
free(matrix[i]);
free(matrix);
}
Then you can create the matrix from main like this:
int main(int argc, char **argv)
{
if(argc < 2)
{
fprintf(stderr, "usage: %s dim\n", argv[0]);
return 1;
}
// just an example of how to convert,
// you could also use strtol
size_t dim = atoi(argv[i]);
int **matrix_a = matrix_create(dim);
if(matrix_a == NULL)
return 1;
int **matrix_b = matrix_create(dim);
if(matrix_b == NULL)
{
matrix_free(matrix_a);
return 1;
}
do_something_with(matrix_a, matrix_b, dim);
matrix_free(matrix_a);
matrix_free(matrix_b);
return 0;
}
Note that I used calloc instead of malloc, because calloc has the benefit
to set 0 to the allocated memory. It's great for initializing and error
handling, because free(NULL) is allowed, so as you see when allocating memory
for the matrix[i] rows, if something goes wrong, I can safely use
matrix_free on the whole matrix.

Related

Is there anyway to decide the amount of array while running your code?

I'm trying to write a beginner c code when you get unknown amount of integers from user and process them. Since it's is not valid to initialize a array of integers without deciding the size, i wonder if i could do some trick to make my code more efficient. Currently I'm initializing an array with size of 999 and ask user not to go beyond this border.
example code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[999];
printf("After entering numbers enter -1 to stop: \n");
for(int i=0;i<999;i++)
{
printf("Enter number(%d): ",i+1);
scanf("%d",&a[i]);
if(a[i]==-1) break;
if(i==998)
{
printf("Max limit reached.");
break;
}
}
//some code for processing the numbers
}
2 options: a) ask the user how many items and use a Variable Length Array (added to Standard C in C99; made optional in C11) ... or b) use dynamic memory and keep growing the array.
option a)
printf("enter number of items: ");
fflush(stdout);
char input[100];
fgets(input, sizeof input, stdin); // error checking ommited
size_t n = strtol(input, 0, 10); // error checking ommited
int array[n]; // VLA
// use array
option b)
size_t reserved = 5; used = 0;
int *array = malloc(reserved * sizeof *array); // start with space for 5 items
for (;;) {
if (used == reserved) {
// grow array
reserved *= 2;
int *tmp = realloc(array, reserved * sizeof *tmp);
if (!tmp) exit(EXIT_FAILURE); // not enough memory
array = tmp;
}
array[used++] = getint(); // get integer from user/file/network/...
// find way to leave for loop
}
// optionaly shrink the array
if (used < reserved) {
int *tmp = realloc(array, used * sizeof *tmp);
if (!tmp) exit(EXIT_FAILURE);
array = tmp;
}
// use array
free(array);
Option b) is preferred if the number of items can be large so as to not cause a stack overflow.
One sensible option is to forget about scanf and use command-line arguments instead. Faster, potentially safer (if you add an upper-bounds check), less memory consumed.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[])
{
if(argc < 2) // or if(argc < 2 || argc > SOME_UPPER_LIMIT)
return 0;
size_t size = argc-1;
int input [size];
for(size_t i=0; i<size; i++)
{
input[i] = strtol(argv[i+1],NULL,10);
printf("%d ", input[i]);
}
}
Execute as for example: myprog 12 34 56 78 -> Output 12 34 56 78.
you can use this also :
#define MAXSIZE 999
void getNums(int nums[]){
int i = 0, temp;
char c;
while(((c=getchar())!='\n') && (i < MAXSIZE-1)){
temp = c - '0';
nums[i] = temp;
i++;
}
nums[i] = '\0';
}
int main(){
int nums[MAXSIZE];
getNums(nums);
return 0;
}

Input of integers' array of unknown size

I'm trying to create an array of integers of an unknown size.
Every time I input a positive element I use realloc to increase the size of the array and store that element
The thing is that when I run this code, I get a run-time error after 2 iterations of the while of the function create1DArray, so it's probably due to a realloc failure.
Can anybody tell me what I did wrong and how to fix it?
Thanks in advance,
#include <stdio.h>
#include <stdlib.h>
void create1DArray(int** perArray, int* size);
int main()
{
int *perArray, size=0, i;
create1DArray(&perArray, &size );
for(i=0; i<size; i++)
printf("%d ",perArray[i]);
free(perArray);
return 0;
}
void create1DArray(int** perArray, int* size)
{
int flag=0, i=0, x;
*perArray=(int*)malloc(sizeof(int) );
if(*perArray==NULL)
{
printf("Allocation failed!");
exit(1);
}
while(!flag)
{
if( scanf("%d", &x)<1 || (x<0) )
{
printf("Invalid input!");
free(perArray);
exit(1);
}
if(!x)
{
if( !(*size) )
{
printf("The first element of the array must not be 0");
free(perArray);
exit(1);
}
flag++;
}
else
{
*perArray=(int*)realloc(*perArray, (++(*size))*sizeof(int) );
if(*perArray==NULL)
{
printf("Reallocation failed!");
free(perArray);
exit(1);
}
*perArray[i++]=x;
}
}
}
I think I see two problems (and M Oehm spotted one more):
1) Your handling of size is wrong (or at least strange). Normally you'll do something like:
*perArray=(int*)malloc(sizeof(int) );
*size = 1;
Perhaps even better - you should drop the malloc and just initialize the pointer in main to NULL. realloc works like malloc when called with NULL.
This would also allow you to call the function several times - something you current code doesn't allow.
2) There is a problem with your realloc
*perArray=(int*)realloc(perArray, (++(*size))*sizeof(int) );
^^^^
Should be *perArray
3) You need to dereference the pointer before indexing (noticed by M Oehm - thanks).
*perArray[i++]=x; ---> (*perArray)[i++]=x;
May not be exactly what you want, but take a look at how it can be done concisely (although doing realloc at each iteration is inefficient). It should be compiled with the flag std=c11.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int size = 0;
int input = 0;
int * perArray = NULL;
while(scanf("%d", &input) && input > 0)
{
++size;
perArray = (int *) realloc(perArray, sizeof(int) * (long unsigned) size);
assert(perArray);
perArray[size - 1] = input;
}
if(perArray)
{
for(int i = 0; i < size; ++i) printf("%d ", perArray[i]);
printf("\n");
free(perArray);
}
return 0;
}

2D array (pointer to pointer)

I want to fill 2D array with random numbers and then call it in main function and print it. But I can't access the function FillMatrix from main.
#define R 12 //row
#define S 10 //column
void FillMatrix(int m[][S], int row);
int main(int argc, char *argv[])
{
int i, j;
time_t t;
// POINTER TO POINTER
int **mat = (int **)malloc(R * sizeof(int *));
if ((mat = (int**)malloc(R*sizeof(int))) == NULL)
{
printf("Error");
return 0;
}
for (i = 0; i<R; i++)
mat[i] = (int *)malloc(S * sizeof(int));
FillMatrix(mat, R); //<- This line is the problem
// RAND 0 - 1000
}
void FillMatrix(int m[][S], int row)
{
int i, j;
time_t t;
srand((unsigned)time(&t));
for (i = 0; i < row; i++)
for (j = 0; j < S; j++)
m[i][j] = rand() % 1000 + 0;
}
(mat = (int**)malloc(R*sizeof(int)) allocates the wrong amount of space; the type should be sizeof(int *) or equivalently sizeof *mat. Also you leak the memory you just allocated on the previous line.
To fix this, change if ((mat = (int**)malloc(R*sizeof(int))) == NULL) to if ( mat == NULL ) .
Also, int ** is not compatible with int[][S]. int ** represents an array where each line is a separate allocation, however int [][S] represents one contiguous memory block. You must choose which of those two approaches you want to use.
If you want to use the separate rows, then change the function to void FillMatrix(int **m, int row) (and it would be good style to have the number of columns as a parameter, instead of using the global S).
Or if you want to use the contiguous memory block, change the allocation line to int (*mat)[S] = malloc(R * sizeof *mat);
Well, you're code is off a bit. I'm going to assume that your main function starts right before int i, j; and ends after the call to FillMatrix(mat, R);.
If that is the case then you need to either move your function definition of FillMatrix before you start your main function OR you need to forward declare your FillMatrix function before your main function.
The issue is that your main function cannot "see" your FillMatrix function. Order is VERY important. If something has not been declared, defined, or in some way shown to exist AT THE POINT IN QUESTION then it doesn't exist as far as the compiler is concerned. Think of it like trying to access some variable before you declare it in a function.

Initialising an int array in an if statement and using externally

New to C here and would appreciate if I could get some pointers.
I'm trying to initialise an array inside an if statement, and then print the values of the array externally - but I know the scope will be lost after the if block ends. I've tried creating the array with pointers. The reason I'm doing it inside the if statement is because the size of the array depends on a value calculated during runtime.
E.g.:
void createArray() {
int userInput;
printf("%s\n", "Please enter a value:");
scanf("%d\n", userInput);
if (userInput > 10) {
int array[userInput];
}
int i;
for (i = 0; i < userInput; i++) {
array[i] = i;
}
}
int i;
for (i = 0; i < sizeof(array)/sizeof(array[0]); i++) {
printf("%d\n", array[i]);
}
However because the array is declared inside a method, I obviously lose scope of it when it comes to the final for loop to print - thus an error occurs. I've tried creating a pointer variable int *array as a global variable, and inside the if statement, just staying array = int[10] but obviously this won't work.
This isn't my exact code, I've recreated a minimal example that shows my error so some syntax may be wrong here - apologies for that.
Any help would be appreciated.
One question you have to consider in your code is what happens if userInput is less than or equal to 10? You iterate over userInput elements of an array that was not declared.
One simple way of handling this is to make a large array at the beginning of your function and then use just the first userInput elements of it. This approach has obviously its limitations (e.g. userInput can't be larger than the size of the array, and you should make sure it won't be, otherwise bad things may happen), but is simple.
Another approach involves using dynamic memory allocation. This is done by using the malloc function:
int *array = malloc(100 * sizeof(int));
The code above allocates memory for 100 ints, basically creating an array of 100 elements. Then, you can use the array as usual. But, make sure you free it after you're done:
free(array);
Note that using this approach you'd need to declare the pointer first:
int *array;
if (userInput > 10) {
array = malloc(userInput * sizeof(int));
}
Below you can find a small proof of concept program. Note that instead of a global variable, the pointer value can be returned from the alloc function.
#include <stdio.h>
#include <stdlib.h>
int *arr;
void alloc() {
arr = malloc(10 * sizeof(int));
}
void assign() {
for (int i = 0; i < 10; i++)
arr[i] = i + i;
}
void print() {
for (int i = 0; i < 10; i++)
printf("%d\n", arr[i]);
}
int main(int argc, char *argv[])
{
alloc();
assign();
print();
free(arr);
return 0;
}
This allocates an array of int to the pointer intary. The pointer may be passed to other functions from main(). In main, userInput stores the number of int allocated.
#include <stdio.h>
#include <stdlib.h>
int *createArray( int *userInput);
int main( int argc, char *argv[])
{
int i;
int userInput = 0;
int *intary = NULL;
if ( ( intary = createArray ( &userInput)) != NULL ) {
for (i = 0; i < userInput; i++) {
intary[i] = i;
printf ( "%d\n", intary[i]);
}
free ( intary);
}
return 0;
}
int *createArray( int *userInput) {
int *array = NULL;
printf("%s\n", "Please enter a value:");
scanf("%d", userInput);
if ( *userInput > 10) {
if ( ( array = malloc ( *userInput * sizeof ( int))) == NULL) {
printf ( "could not allocate memory\n");
*userInput = 0;
return NULL;
}
}
else {
*userInput = 0;
return NULL;
}
return array;
}
You don't need some pointers, just one, (int* arr) and malloc(),a dynamic memory allocation function.
Note: You shouldn't use "array" as a variable name as it may create problems. So we'll name our variable arr.
If you're unfamiliar with it, i will explain the code too.
First add #include <stdlib.h> header file, which contains malloc().
Then declare a pointer of type int int* arr, we have named it arr in the createArray() scope.
We'll allocate the space required in the if condition with malloc() function, like :
void createArray() {
int userInput;
int* arr; // declare arr pointer
printf("%s\n", "Please enter a value:");
scanf("%d\n", userInput);
if (userInput > 10) {
arr = (int*) malloc ( userInput * sizeof(int) ); // explained below
}
int i;
for (i = 0; i < userInput; i++) {
arr[i] = i;
}
}
free(arr) // don't forget to free after using
[NOTE] This code is untested.
arr = (int*) malloc ( userInput * sizeof(int) );
This line may seem cryptic at first, but what it does is pretty simple , it allocates some memory dynamically on the heap.
The size of this memory is given by 'userInput * sizeof(int)', sizeof() function specifies the size of int on the given machine multiplied by userInput by the user,
Then, it is typecasted to int* type so that we can store the address in our int* type pointer arr.
[UPDATE] you can use arr = malloc ( userInput * sizeof(int) ); instead as suggested in comments, here is why Do I cast the result of malloc?

Passing 2d array char into function

I'm trying to pass a 2D array with strings in it into a function. I keep getting the
expected expression before ] token.
The point of this code is to read in a wordsearch puzzle, then find the words in that puzzle. I'm going to be writing a function for forward search, backword search, and then up and down search.
How do I get rid of this error? The error is down at the very bottom where I call the forward function.
/*Andrea Hatfield CPE 101 October 31st, 2012*/
#include <stdio.h>
#include <string.h>
int forward(char words[][8], char puzzle[][11]);
int main()
{
char puzzle[11][11];
char words[8][8];
FILE *fin, *fwords;
int i = 0;
int j= 0;
fin = fopen("puzzle.in", "r");
fwords = fopen("words.in", "r");
if(fin == NULL) /*Reads in the puzzle file*/
printf("File does not exist");
else
{
while(fscanf(fin,"%s", puzzle[i])!=EOF)
{
printf("%s\n", puzzle[i]);
i++;
}
}
if(fwords == NULL) /*Reads in the words the puzzle will search for */
printf("File does not exist");
else
{
while(fscanf(fwords, "%s", words[j])!=EOF)
{
printf("%s\n", words[j]);
}
}
forward(&words[][8], &puzzle[][11]); /*Error at this point*/
return(0);
}
It is a little bit hard to get what you want to do but there is a problem in here:
forward(&words[][8], &puzzle[][11]);
try this instead:
forward(words, puzzle);
Here are two other options that should be mentioned from here:
#define ROWS 4
#define COLS 5
void func(int array[ROWS][COLS]) {
int i, j;
for (i=0; i<ROWS; i++) {
for (j=0; j<COLS; j++) {
array[i][j] = i*j;
}
}
}
void func_vla(int rows, int cols, int array[rows][cols]) {
int i, j;
for (i=0; i<rows; i++) {
for (j=0; j<cols; j++) {
array[i][j] = i*j;
}
}
}
int main() {
int x[ROWS][COLS];
func(x);
func_vla(ROWS, COLS, x);
}
You need to call directly
forward(words, puzzle);
However, you have an error in your code: you forgot the j++ in the reading cycle while reading words, so you are overwriting words[0] and not initialising the other members of the array.
Also, in a real world situation, you might find it desirable to choose the array size at run time. A simple way to do it would be to choose a reasonably large limit for both width and height, and go with 0x90's solution (you need a 30x20 puzzle, and you can handle it easily since you compiled with ROWS and COLS equal to, say, 1024).
A more complicated way would be to use malloc() (using pointers to pointers to chars) and allocate both arrays dynamically, limited by available memory; you would then pass their dimensions to the forward function.
int forward(char **words, char **puzzle, size_t w_w, size_t w_h, size_t p_w, size_t p_h)
{
}
Yet, the allocation part would be more complicated given the looped calls to malloc() and the need to check its return value every time to intercept out-of-memory conditions; also, in some scenarios you might want the memory to be deallocated (e.g. to run repeated puzzles), which leads to further complexity.

Resources