I'm new to C and I'm having a hard time grasping the concept of making arrays.
I created the first 2d array to get the inputs by initializing the maximum possible entries I can have.
int max;
scanf("%d", &max);
int(*first)[n] = malloc(sizeof(int[n][n]));
After encoding the inputs, I have different unused space for every first[i] since each has different length. I received a memory limit exceeded so I would like to remove unused spaces. So, I created the second array and was planning to copy only the used spaces in the first array but I can't initialized the second array.
int second[n];
for (int i = 0; i < n; i++)
{
int len = length of first[i];
int length[len];
second[i] = length;
}
There are specialized data structures optimized for these cases, like sparse matrix, but they may be a bit difficult to implement depending on your level of knowledge.
An easy solution (at the cost of fragmenting the memory) is to use the first element of each row as a sentinel indicating the number of columns that the row is going to have, I omit the error checks for brevity:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand((unsigned)time(NULL));
size_t rows = (size_t)(rand() % 10 + 10);
int **array = malloc(sizeof *array * rows);
for (size_t row = 0; row < rows; row++)
{
int cols = rand() % 10 + 1;
array[row] = malloc(sizeof **array * (size_t)(cols + 1));
array[row][0] = cols;
for (int col = 1; col < cols + 1; col++)
{
array[row][col] = rand() % 10;
}
}
for (size_t row = 0; row < rows; row++)
{
int cols = array[row][0];
printf("%d cols: ", cols);
for (int col = 1; col < cols + 1; col++)
{
printf("%d ", array[row][col]);
}
printf("\n");
free(array[row]);
}
free(array);
return 0;
}
Output:
9 cols: 7 7 4 7 4 7 5 6 9
2 cols: 6 6
3 cols: 4 6 7
2 cols: 4 6
6 cols: 4 0 9 3 6 0
7 cols: 0 7 2 9 4 1 3
2 cols: 6 0
9 cols: 2 0 9 0 8 2 4 4 1
9 cols: 0 7 5 7 8 4 2 4 6
9 cols: 4 3 3 3 8 4 8 1 2
2 cols: 0 4
2 cols: 1 5
2 cols: 5 1
7 cols: 6 1 8 4 6 5 4
3 cols: 7 0 9
9 cols: 6 2 3 2 2 7 0 6 0
When you have a 2D array and don't know the size of each element, make an array of pointers. Then allocate exactly as much memory you need for each individual element.
A simple example would be storing each line of a file. Each line is an array of characters, but you don't know how long a line can be. It would be a huge waste to allocate a 2D array large enough to hold the biggest possible line. Instead, allocate a char **. This will be a list of char * strings.
const int max_lines = 1024;
char **lines = malloc(sizeof(char*) * max_lines);
This is 1024 pointers. Each pointer is only 4 or 8 bytes. So only about 8k of memory. There are ways to also avoid needing to allocate a fixed size here, but that's another answer.
Then read each line and only store as much as you need for each line.
int i = 0;
char line[BUFSIZ];
while( fgets(line, sizeof(line), stdin) ) {
lines[i] = strdup(line);
i++;
}
line is allocated using BUFSIZ to be large enough to fit most any line. And we reuse that to read lines of the file. But instead of storing all that extra memory, we use strdup to copy the line to the minimum memory and store a pointer to that in lines.
Related
I have this assignment to get and transpose a matrix using dynamic memory allocation in C
I did it by converting the linear position to (i,j) and swapping i,j
old and new element positions are perfect,
somehow the swap is not working as i intended,
might seem like i'm making others problem solve for me, but i'm blank at this point so help will be really appreciated
Here's the code:
#include <stdio.h>
#include <stdlib.h>
int main(){
int m,n;
printf("Enter the order of matrix, m*n:\n");
scanf("%d %d",&m,&n);
int *matrix_ptr;
matrix_ptr = (int *) malloc(m*n*sizeof(int));
printf("Enter the elements of %d*%d matrix\n",m,n);
for(int i=0; i<m*n; i++){
scanf("%d", matrix_ptr+i);
}
// Transposing the matrix
for(int i=0; i<m*n; i++){
int i_index = i / n;
int j_index = i % n;
// (i_index)*n + j_index gives the linear position
int new_linear_pos = (j_index)*n + i_index;
int temp = *(matrix_ptr + new_linear_pos);
*(matrix_ptr + new_linear_pos) = *(matrix_ptr + i);
*(matrix_ptr + i) = temp;
if(i==0){
printf("\nThe transpose is:\n");
}
printf("%d ", *(matrix_ptr+i));
if((i+1)%n == 0){
printf("\n");
}
}
}
The output:
You are swapping all values twice and you are printing the ones at the beginning of the line after the second swap. The first swap happened with i equal 1 and 2
Let's say you have this matrix at the begin:
1 2 3
4 5 6
7 8 9
swap index 0 with 0 stays the same thing. Prints 1
swap index 1 with 3: prints 4
1 4 3
2 5 6
7 8 9
swap index 2 with 6: prints 7\n
1 4 7
2 5 6
3 8 9
swap index 3 with 1: prints 4
1 2 7
4 5 6
3 8 9
etc...
The solution would be to swap elements only once.
The easiest fix would be a if (i > new_linear_pos) continue; //already swapped
My code is very likely to be incorrect everywhere since I just go started on learning files.
The array of the text file is {3 2 1 3 4 5 6 1 2 3}
The array of the binary is {1 2 3 4 5 6 7 8 9 10}
#include <stdio.h>
#define ARR_SIZ 10
int main()
{
int arr_in[ARR_SIZ];
int arr_bin[ARR_SIZ];
int i = 0;
FILE * fp_in = fopen("data/in.txt", "r");
FILE * fp_bin = fopen("data/in.bin", "wb");
fread(arr_in, sizeof(int), ARR_SIZ, fp_in);
fread(arr_bin, sizeof(int), ARR_SIZ, fp_bin);
int sum[ARR_SIZ];
for (i=0; i < ARR_SIZ; i++){
fscanf("%d", arr_in);
fscanf("%d", arr_in);
sum[i] = arr_in[i] + arr_bin[i];
} printf("%d", sum[i]);
return 0;
}
fread() reads binary data even when the file is not opened with "b" which just means it doesn't do funny stuff with things like Windows-style line breaks.
If you want to read a text file you will how to do more complex work like reading in the data, look for line breaks, and than use the data before each line break. As that data is still a string you will need to convert it to an integer (e.g. using atoi())
You can use this simple program (without fread()):
#include <stdio.h>
#define SIZE 10
int main(void) {
FILE *text = fopen("in.txt", "r"); // --- declaration
FILE *binr = fopen("in.bin", "r");
int text_number[SIZE], binary_number[SIZE], sum = 0;
// alt: you can change sum to sum[SIZE] = {0} if you want to hold into an array.
// --- reading data and assigning into arrays
for (int i = 0; i < SIZE; i++) {
fscanf(text, "%d", &text_number[i]);
fscanf(binr, "%d", &binary_number[i]);
}
// --- summation
for (int i = 0; i < SIZE; i++) {
sum += text_number[i] + binary_number[i]; // alt: do sum[i] when you do sum[SIZE]
printf("%d ", sum); // alt: do sum[i]
sum = 0; // should be omitted when you change into sum[SIZE]
}
printf("\n");
return 0;
}
in.bin contains: 1 2 3 4 5 6 7 8 9 10
Similarly, in.txt contains: 3 2 1 3 4 5 6 1 2 3
And the result is: 4 4 4 7 9 11 13 9 11 13 (sum of both files' integers taken by array).
Note: If you want to store the sum into array, then use the alt code.
I'm not very much aware of fread(), so I just did what I could at the moment.
I just worked to my final exam with simple codes; when I try to sorting strings, I face annoying error. Why 2 is not smaller than 10 on my CodeBlocks IDE but is smaller than 10 on real and onlinegdb.com?
This is the annoying code:
#include <string.h>
#include <stdio.h>
#define STR_SIZ 20
int main()
{
char strArr[][STR_SIZ] = {"abc", "hdas", "sdfasf", "kakldf", "caksl", "casd", "keam", "cznjcx", "mnxzv", "jkalkds"};
char minStr[STR_SIZ];
strcpy(minStr, strArr[0]);
int N = sizeof(strArr)/sizeof(minStr);
// int N = 10;
for(int x = 0; x < N-1; x++)
{
printf("%d", x);
strcpy(minStr,strArr[x]);
int j;
for(j=1+x; j < 10; j++)
{
printf("%4d\n", j);
int cmp = strcmp(strArr[j], minStr);
if(cmp < 0)
strcpy(minStr,strArr[j]);
}
char temp[STR_SIZ];
strcpy(temp,strArr[x]);
strcpy(strArr[x], minStr);
strcpy(strArr[j], temp);
}
return 0;
}
Output on onlinegdb.com:
0 1
2
3
4
5
6
7
8
9
1 2
3
4
5
6
7
8
9
2 3
4
5
6
7
8
9
3 4
5
6
7
8
9
4 5
6
7
8
9
5 6
7
8
9
6 7
8
9
7 8
9
8 9
Output on CodeBlocks:
0 1
2
3
4
5
6
7
8
9
1 2
3
4
5
6
7
8
9
2
PS: I just have used Codeblock in the morning and it was okey with executing.
strArr has 10 elements. At the end of your loop, you call strcpy(strArr[j], temp);. This will write to strArr[10], which is out of bounds and will overwrite some unknown memory. Anything can happen after that.
You should save the j value when you copy a string into minStr.
FYI, your code above prints this as your final string order with onlinegdb:
abc
caksl
caksl
caksl
caksl
casd
cznjcx
cznjcx
jkalkds
jkalkds
So I think you have other problems as well.
try this
#include <string.h>
#include <stdio.h>
#define STR_SIZ 20
int main()
{
char strArr[][STR_SIZ] = {"abc", "hdas", "sdfasf", "kakldf", "caksl", "casd", "keam", "cznjcx", "mnxzv", "jkalkds"};
strcpy(minStr, strArr[0]);
// Calculate the number of elements this way.
const int N = sizeof(strArr)/sizeof(strArr[0]);
// int N = 10;
for(int x = 0; x < N-1; x++)
{
printf("%d", x);
int j;
for(j=1+x; j < N; j++) // Use N here too!
{
printf("%4d\n", j);
int cmp = strcmp(strArr[j], strArr[x]);
if(cmp < 0)
{
// Do the swaps only when needed.
char temp[STR_SIZ];
strcpy(temp,strArr[x]);
strcpy(strArr[x], strArr[j]);
strcpy(strArr[j], temp);
}
}
}
// Verify result
for(int x = 0; x < N; x++) printf("%s\n", strArr[x]);
return 0;
}
I moved your swap into your if check and got rid of your minStr as it was not needed. Notice how I calculate the N size too. Honestly, you were close, but you needed to verify your output.
I tried to sort arr by excluding those who were already selected as the largest numbers but it didn't work.
The result is this:
As I intended, at first cycle, the store is {9, 0, 0, 0, 0 ... } and when arr[i] becomes 9, the rest of process should be skipped. I have to sort it without additional functions and it's too difficult to me. What is the problem?
int i = 0;
int j = 0;
int num = 0;
int sign = 0;
int arr[10] = { 1,5,3,4,8,7,5,9,8,0 };
int max = arr[0];
int store[10] = { 0 };
int k = 0;
for (j = 0; j < 10; j++) {
printf("store: ");
for (int n = 0; n < 10; on++)
printf("%d ", store[n]);
printf("\n");
for (i = 0; i < 10; i++) {
sign = 0;
k = 0;
while (k < 10) {
if (arr[i] == store[k]) {
sign = 1;
break;
}
k++;
}
if (sign == 1) {
continue;
}
if (arr[i] > max) {
max = arr[i];
}
}
store[j] = max;
}
You have several errors here:
The array store has a size of 10, but in the jth pass through the outer loop, only j values have been filled in; the rest is still zero. So whenever you iterate over store, you should use j as upper limit.
You are looking for the max in each iteration. Therefore, it is not enough to initialise max once outside the outer loop. You do that, and it will stay 9 ever after. You should reset max for every j.
Finally, your idea to go through the array to see whether you have already processed a certain value does not work. Your array has duplicates, two 8's and two 5's. You will only place one eight and one five with your strategy and re-use the last value of max for the last two elements. (Plus, that idea lead to O(n³) code, which is very wasteful.
You can work around that by keeping an extra array where you store whether (1) or not (0) you have already processed a value at a certain index or by setting processed entries in the array to a very low value.
What you want to implement is selection sort: Find the maximum value in the whole list and move it to the front. Then find the maximum in the whole list except the first item and move it to the second slot and so on:
* 1 5 3 4 8 7 5 9 8 0
9 * 5 3 4 8 7 5 1 8 0
9 8 * 3 4 5 7 5 1 8 0
9 8 8 * 4 5 7 5 1 3 0
9 8 8 7 * 5 4 5 1 3 0
9 8 8 7 5 * 4 5 1 3 0
9 8 8 7 5 5 * 4 1 3 0
9 8 8 7 5 5 4 * 1 3 0
9 8 8 7 5 5 4 3 * 1 0
9 8 8 7 5 5 4 3 1 * 0
9 8 8 7 5 5 4 3 1 0 *
Here, all items to the left of the asterisk have been sorted and everything to the right of the asterisk is still unsorted. When the * (at position j) has moved to the right, the whole array is sorted.
This sort is in-place: It destroys the original order of the array. That is useful, because the position of an element tells us whether it has been processed or not. In the third iteration, the algorithm can distinguish between the 8 that has been sorted and the 8 that hasn't been sorted yet. (This sort is often described as sorting a hand of cards: Look fo the lowest, put it to the left and so on. If you must sort into a second array, copy the original array and sort the copy in place.)
Here's the code that sorts your array and prints out the diagram above:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int arr[10] = {1, 5, 3, 4, 8, 7, 5, 9, 8, 0};
int i = 0;
int j = 0;
for (j = 0; j < 10; j++) {
int imax = j;
int swap = arr[j];
// print array
for (i = 0; i < 10; i++) {
if (i == j) printf("* ");
printf("%d ", arr[i]);
}
printf("\n");
// find index of maximum item
for (i = j + 1; i < 10; i++) {
if (arr[i] > arr[imax]) {
imax = i;
}
}
// swap first unsorted item and maximum item
arr[j] = arr[imax];
arr[imax] = swap;
}
// print fully sorted array
for (i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("*\n");
return 0;
}
Use i and j.
N is 10 and the data consists of shuffled numbers 0 to N-1.
j goes from 0 to N-1. At each step, you want to fill it with
the maximum of the unprocessed input.
So i goes from j+1 to N-1, in the inner loop. If arr[j] < arr[i],
swap arr[i] and arr[j].
It speeds up considerably as you get towards the end.
Given an array of size L1xL2 divide the array by blocks of 4x4. For example the size of the array is 8x8 so there will be four blocks of 4x4.
Here is an example:
1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 8 8 8 8
...............
First block 4x4 will be:
1 1 1 1 3 3 3 3 5 5 5 5 7 7 7 7
The second block will be:
2 2 2 2 4 4 4 4 6 6 6 6 8 8 8 8
I wrote this code (I have a matrix that is stored as an array and it's size is 8*8):
for (p = 0; p < nr_blocks; p ++) {
for (i = p*4; i < p*4 + 4; i++) {
for (j = 0; j < 4; j++) {
printf(" %d ", array[i*4 + j]);
}
}
}
But this code take the first block like this:
1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4
I want to divide in all the blocks and print them => 4 blocks.
What it is wrong?
When your array stores the 8x8 matrix you need access it with the dimension 8.
for(p = 0; p < nr_blocks; p ++){
for(i = p*nr_blocks; i < p*nr_blocks + 4; i++) { // please note the change
for(j = 0; j < 4; j++){
printf(" %d ", array[i*4 + j]);
}
printf("\n");
}
}
You seem to be storing what you call a matrix as one array, that is not a matrix. A matrix is
an array of arrays, thats what is making this difficult for you.
for (p = 0; p < nr_blocks; p ++) {
for (i = p*4; i < p*4 + 8; i=i+2) {
for (j = 0; j < 4; j++) {
printf(" %d ", array[i*4 + j]);
}
}
}
First
You are describing a 2 dimensional array, but using a 1 dimensional array in your code.
Second
Keep in mind C arrays are row major order. The order you extract elements must obey that construct.
For example, given this 3X4 array: (3 rows, 4 columns)
|1 1 1 1|
|2 2 2 2|
|3 3 3 3|
A C variable to contain such a matrix could be defined as:
int array[3][4]={{1,1,1,1},{2,2,2,2},{3,3,3,3}};
In memory, although it is a 2 dimensional array the elements are stored contiguously (Starting from array[0][0]) like this:
1 1 1 1 2 2 2 2 3 3 3 3
The offset from the beginning of the array to any one element is given by:
offset = row * (number_of_columns) + column;
Working in the opposite way, if you have an element's linear offset, you can get the row or column as follows:
row = offset/(number_of_columns);
column = offset%(number_of_columns);
In the example data you have shown (before you edited your original post), row 1 contains 4 1s, & 4 2s, then row 2: 4 3s & 4 4s, and so on. In extracting, you would have to set your for loop indexes to go from 0 to 3 for each of the 4 rows as you traverse the columns to get the first block. Then use 4 to 7 to traverse the columns again on the same 4 rows to get the second block.
For an 8x8, the same procedure would be used. Just keep in mind the row major order of the array.
Getting the first blocks for 8x8:
int i, j, r=8, c=8;
//first row 2nd 3rd and so on
int array[8][8]={{1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4},{...},{...}, (8 blocks total)...};
for(i=0;i<r/2;i++) //traverse 4 of 8 rows
for(j=0;c/2<j++) //traverse 4 of 8 columns
printf(" %d ", array[i][j]); //note this array is a two dimensional array,
//while you are showing a 1 dimensional array in your example
//(this is only 1 dimensional: array[i*4 + j])
Change indexes accordingly for remaining blocks