Sort numbers from a .txt file in C - c

I made a sorting algorithm that works alright when the numbers I need to sort are in an array inside the code, like this:
int sort[] = {16,8,23,4,42,15};
But I need the code to sort the numbers from a .txt file, I do know the size of the file (so no need of a sizeof to know how many numbers you need to sort) but the problem is that the numbers in the file are not separated by commas, only spaces, and I don't know how to make my code operate with this list of numbers.
My code is like this, and like I said, it works when the sorting array of numbers is inside the code separated by comas:
int main(){
int temp, size;
int sort[] = {16,8,23,4,42,15};
size = sizeof(sort) / sizeof(int);
for(int j = 0; j < size; j++){
for(int i = 0; i < size; i++){
if(sort[i] > sort[i+1]){
temp = sort[i];
sort[i] = sort[i+1];
sort[i+1] = temp;
}
}
}
for(int p = 0; p < size; p++){
printf("%d ", sort[p]);
}
}
And I also know that to open a file in C the code is something like this:
FILE* f;
f = fopen("1000.txt", "r");
if(f == 0){
printf("Database unavaible or corrupted\n\n");
exit(1);
}
But I don't know what do next, how do I get this file with unsorted numbers not separated by commas and make my code sort and print them?

You can use fscanf to read the number from file then store these numbers in an array. Finally, you can using your sorting function to sort the this array.
The code below is an example for reading the numbers from the file:
#include <stdio.h>
#define MAX_NUM 10
int main() {
FILE * fp = fopen("input.txt", "r");
if(!fp) {return -1;}
int array[MAX_NUM] = {0}; // you can use array[size] if you know exactly how many numbers in the file
int i = 0;
while(i < MAX_NUM && fscanf(fp, "%d", &array[i]) == 1) {
printf("a[%d] = %d\n", i, array[i]);
i++;
}
// sort the array here as you did in your code
return 0;
}
OT, your code has a mistake in for loop:
for(int i = 0; i < size; i++){
if(sort[i] > sort[i+1]){...}
...
}
when i = size - 1, sort[i+1] will become sort[size] that is out of the array sort, because the maximum index that you can access is size-1 not size. It should change to:
for(int j = 0; j < size; j++) {
for(int i = 0; i < size-j-1; i++) {...}
}

To read the numbers you can use fscanf but you still have the problem of memory allocation.
Imagine the file has 20 elements but the MAX_NUM is 4096, you would be taking 4086*4 bytes of memory unnecessarily.
On the other hand the file can have 8000 elements but you can only store 4096.
What you can do is dynamic memory allocation.
int *array = (int*)malloc(10*sizeof(int));
unsigned numbers_counter = 0;
while(fscanf(f,"%i",&array[numbers_counter++])==1){
if(numbers_counter>=sizeof(array)){
if((array = (int*) realloc(array,sizeof(int)*sizeof(int)*10)) == NULL)
exit(1);
}
}
What I do in this segment is allocate a space of 10 int on memory, then, when the array is full (if(numbers_counter>=sizeof(array))) the array for a bigger set of numbers.
If you have until 10 numbers, it only occupies 10*4 bytes, the from 11 to 100 it occupies 100*4, etc.

Related

For my C code, where I am reading a file and sorting it is giving me garbage outputs. Why?

I am doing an assignment which is:
Find k largest elements of a file. Allocate an array of size k and while you read the numbers from the file, store the k largest numbers in the array. When you read the next element from the file, find if the array needs to be modified or not. Assume that next element read is 80. Since 80 is larger than the smallest element, we need to shift elements < 80 to the right by 1 position and create space for 80. In main() use argc and argv to read the filename and k from the user and compute and print the k largest elements. Name your program assign3.c First parameter is filename and second parameter is k. You need to use atoi()in stdlib.h to convert strings to integer.
My problem is that I am getting garbage values for both arr and sorted arr?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
int main(int argc, char *argv[])//
{
FILE *iFile;//file pointer
int i = 0, n, temp = 0, count = 0, j;
int k = atoi(argv[1]);//convert strings into int
int *arr = (int *)malloc(k * sizeof(int));////allocate an array of size k
iFile = fopen("a.txt", "r");//opens file
if (iFile == NULL)
return -1;
while (feof(iFile) <= 0)
{
fscanf(iFile, "%d", arr);
printf("arr= %d\n", arr);
count = count++;
for (i = 0; i < count; i++) //Loop for descending ordering
{
for (j = 1; j <= count; j++) //Loop for comparing other values
{
if (arr[j] < arr[i]) //Comparing other array elements
{
temp = arr[i]; //Using temporary variable for storing last value
arr[i] = arr[j]; //replacing value
arr[j] = temp; //storing last value
}
}
}
}
for (i = 0; i < k + 1; i++)
printf("sorted arr is =%d\n", arr[i]);
fclose(iFile);
free(arr);
}
Use a while loop condition like this
While(!feof(iFile))
....
feof() checks whether end of file is reached and returns 0 otherwise

Allocating memory to 2D array using an array of NULL (c)

thanks for taking the time in reading this.
In my question a "vector" is defined as a 1D dimensional array of integers.
Therefore an array of vectors would be a 2D dimensional array in which every vector can be of a different length.
I'm asked to use:
int** vectors- the 2D array
int size -an integer that represents how many vectors exist inside **vectors
int* sizes-a 1D array of integers that represents the length of the vectors
for example,for:
vectors = {{4,3,4,3},{11,22,33,44,55,66},NULL,{5},{3,33,333,33,3}}.
size is 5 (there are 5 vectors inside vectors).
sizes is {4,6,0,1,5} (4 is the length of the first vector and so on).
size is inputted by the user at the beginning of main() and **vectors&*sizes are dynimacilly allocated with size's value.
I'm asked to write the function:
int init(int ***vectors, int **sizes, int size) which initializes **vectors to be an array of NULLs and *sizes to be an array of zeros.
I came up with this code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int init(int*** vectors, int** sizes, int size)
{
int i, k,j;
printf("check\n");
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
*(vectors + i) = NULL;
}
printf("check 2\n");
for (k = 0; k<size; k++)
{
if (*(vectors+k) != NULL)
printf("didn't work\n");
else
printf("current is null\n");
}
*sizes= (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j= 0; j < size; j++)
{
*(sizes + j) = 0;
printf("%d ", *(sizes + j));
}
printf("\n");
return 1;
}
int main()
{
int size, i;
int** vectors = NULL;
int* sizes = NULL;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
printf("%d\n", init(&vectors, &sizes, size));
printf("size is %d now\n", size);
// for (i = 0; i < size; i++)
// printf("%d ", *(sizes+i));
printf("check 3\n");
free(sizes);
free(vectors);
printf("check 4\n");
printf("check 5\n");
return 0;
}
forgot to mention that init returns 0 if it fails to allocate memory and 1 otherwise.
printing the "checks" was so I could see where the program fails.
the problem is that no matter what,after printing the last check (check 5)
the program fails.(Run-Time Check Failure #2)
if anyone could help me understand what I'm doing wrong I would HIGHLY appreciate it.
thanks alot for reading and have an amazing day.
edit:
i also printed the array sizes/vectors inside init just to see if it prints zeros/nulls,i don't actually need to do it.
One problem of OP's code is in the pointer arithmetic. Given:
int ***vectors;
*vectors = malloc(size * sizeof(int*));
This loop:
for (i = 0; i < size; i++)
{
*(vectors + i) = NULL;
}
Would iterate over the next unallocated pointer to pointer to pointer to int, while what the OP needs is
for (i = 0; i < size; i++)
{
*(*vectors + i) = NULL; // or (*vectors)[i] = NULL;
}
The same holds in the following loops, where *(sizes + j) is used instead of *(*sizes + j) (or (*sizes)[j]).

efficient way to get numbers from user and fill Matrix

I want to get numbers from user in a single line for example:
2 1 2 3 4
The first number: 2 means that my Matrix should be with size of 2x2 and the next 4 numbers should insert into my Matrix (Matrix dimension should be n²).
Currently I have this:
int dimension, num;
int *mat;
int numcounter = 0;
int i = 0;
int j, k, t;
char temp;
printf("Please enter numbers: ");
do {
scanf("%d%c", &num, &temp);
i++;
if (i == 1)
{
/* Set Matrix dimension. */
dimension = num;
if (dimension < 2)
{
printf("Size must be a valid number");
return 1;
}
else
/* Allocate dimension size. */
mat = (int*)malloc(dimension * dimension * sizeof(int*));
}
else
{
/* Fill Matrix. */
}
} while (temp != '\n' || temp == EOF)
So here I have all the number and now I need to fill my Matrix but instead of put all the numbers inside temp array and then fill my Matrix I wonder how to do that without another memory allocation.
You can do it simply using a VLA. The OP's initial question never mentioned that OP needs to get the input in a line and parse it. I have given that as an answer in the second part. But simply that is not needed. It is not a feasible reason that you have to get the numbers all at once. You can get the size using one scanf and then the elements in another scanf.
scanf("%d", &num);
//Then you know the dimension of the array.
int arr[num][num];
for(size_t i=0;i<num; i++)
for(size_t j =0; j< num; j++)
if( scanf("%d",&arr[i][j]) != 1)
{
fprintf(stderr,"Error in input");
exit(1);
}
Also as you know how many numbers will be read you don't need to continue scanning until you get '\n' or EOF.
Given your case your over complicating things IMHO. As you know the numbers you can get the benefit of VLA.
If you have to get all the numbers in a single line you need to look at 3 functions. fgets() and strtol. Those will help you achieving reading everything in a line and then tokenizing.
To give you a demo of what I said you can do this
#include <stdio.h>
#include <stdlib.h>
#define BUFSIZE 256
int main(void)
{
char line[BUFSIZE];
long temp[BUFSIZE];
int i = 0;
if (fgets(line, sizeof line, stdin) != NULL)
{
const char *ptr = line;
while (*ptr != '\0')
{
char *endptr = NULL;
long val = strtol(ptr, &endptr, 10);
if (endptr != ptr)
temp[i++] = val;
else
break;
ptr = endptr;
}
}
int sz = temp[0];
if( sz <= 0 )
{
fprintf(stderr,"Error in size input");
exit(1);
}
int tempIn = 1;
long arr[sz][sz];
for(size_t i = 0; i < sz; i++)
for(size_t j = 0; j < sz; j++)
arr[i][j]= temp[tempIn++];
for(size_t i = 0; i < sz; i++)
for(size_t j = 0; j < sz; j++)
printf("%ld ",arr[i][j]);
}
In the second code, as you can see fgets has been used which basically read a line and then strtol has been used. As you have mentioned that you will give a single line input of numbers.
Now what we did?
The line scanned and the parsed number by number using strtol. For a brief overview of strtol check this.
Also OP asked for how to use dynamic memory allocation to do the same thing. And there is no way a while loop is needed here. This is redundant. So while modifying I will add the code that will be able to do it much more simpler way.
scanf("%d", &num);
int matIndex = 0;
/* Set Matrix dimension. */
dimension = num;
if (dimension <= 0)
{
printf("Size must be posiitve integer");
return 1;
}
else
{
mat = malloc(dimension * dimension * sizeof *mat);
if ( mat == NULL ){
fprintf(stderr, "%s\n", "Error in malloc");
exit(1);
}
}
// All the numbers will be taken as elements of the dynamically allocated array,
for(size_t i = 0; i < dimension*dimension ; i++)
if( scanf("%d",&mat[i]) == 1){
//ok
}
else{
fprintf(stderr,"Some error occured");
break;
}
When you want to access the i-th row and j-th column element, you can do this mat[i*dimension+j] //equivalent to mat[i][j]
Some useful information:-
Allocating dim*dim memory doesn't let you access the element in the form of mat[i[[j]. Because you allocated a single chunk of memory - you have to calculate the positions explicitly and access the element in the linear array.
You can do all the scanning using scanf() but you need to be careful when having scanf(). But yes you can get this thing done using scanf also.
Also there is another thing to know about. The VLA will have automatic storage duration and limiting the memory you can have use this way. The dynamically allocated memory has much higher limit giving you a scope of having much larger dimensions array.
Note that in dynamic memory allocation you will need to free the allocated memory when you are done working with it.
If you want to use mat[i][j] not mat[i*dim+j] you can consider creating one jagged array.
Few things that you will need:
Reading Suggestion:
How to debug small programs
Beginner's guide away from scanf
Book list
You can use following code:
Note: You can redirect STDIN to your file. See posts available here
#include <stdio.h>
#include <stdlib.h>
int main()
{
int D, i, j;
freopen("testfile.txt","r",stdin);
printf("Ender dimention of matrix: ");
scanf("%d",&D);
int** matrix = malloc(D*D*sizeof(int));
for(i=0; i<D; i++)
{
for(j=0; j<D; j++)
{
printf("Ender element of matrix: ");
scanf("%d",&matrix[i][j]);
}
}
printf("Matrix is: \n");
for(i=0; i<D; i++)
{
for(j=0; j<D; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
free(matrix);
return 0;
}

Segmentation Fault on Last Iteration

I am trying to randomly fill a 2d array with values then multiply them, but for some odd reason when I run my code, on the last iteration, I get a segmentation fault. I have tried decreasing the number I am passing it and everything, but the fault still persists. Here is the code I am trying to execute, any help is much appreciated, thanks.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *matrixFile;
int n = atoi(argv[1]); // the number of matrices
int i, j; // must declare outside of for loop due to resolve C99 mode error
double arrA[n][n];// = CreateRandomMatrix(n);
double arrB[n][n];
double sumArr[n][n];
matrixFile = fopen("home/acolwell/Documents/CPE631_HW2_Number1/results.txt", "w+");
printf("Usage: %s <size of nxn matrices>\n", argv[1]);
// randomly populate arrA and arrB
for(i = 0; i < n; i++)
{
printf("%d\n", i);
for(j = 0; j < n; j++)
{
printf("%4d", j);
arrA[i][j] = (double)rand()/(double)RAND_MAX;
arrB[i][j] = (double)rand()/(double)RAND_MAX;
}
}
printf("Exiting Matrix randomization");
// multiply the matrices and write them to the file
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
sumArr[i][j] = arrA[i][j] * arrB[i][j];
printf("Writing matrix ");
fprintf(matrixFile, "%0.3lf\n", sumArr[i][j]);
}
}
if(matrixFile)
{
fclose(matrixFile);
}
matrixFile = NULL;
return 0;
}
This error is going to come down to writing off the end of your array or failure to open your file. I would suggest running gdb to check out your program when it is running, but from a quick glance I wonder if you don't mean to have
"/home/acolwell/Documents/CPE631_HW2_Number1/results.txt"
as the file to write instead of
"home/acolwell/Documents/CPE631_HW2_Number1/results.txt"
I would suggest checking the result of your fopen call before calling fprintf.
If n is large enough, you'll generate a stack overflow using VLAs. I've verified this experimentally with your code (e.g. use n of 5000).
So, you'll need to use malloc to allocate from heap. But, that would require a bit of a rewrite.
Here's a way to use heap allocation and get the benefit of a VLA [using some slight trickery]:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C(_arr) (double (*)[(size_t)(n)]) _arr
void
docalc(FILE *fout,int n,double arrA[n][n],double arrB[n][n],double sumArr[n][n])
{
// must declare outside of for loop due to resolve C99 mode error
int i,
j;
// randomly populate arrA and arrB
for (i = 0; i < n; i++) {
printf("%d\n", i);
for (j = 0; j < n; j++) {
printf("%4d", j);
arrA[i][j] = (double) rand() / (double) RAND_MAX;
arrB[i][j] = (double) rand() / (double) RAND_MAX;
}
}
printf("Exiting Matrix randomization");
// multiply the matrices and write them to the file
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
sumArr[i][j] = arrA[i][j] * arrB[i][j];
printf("Writing matrix\n");
fprintf(fout, "%0.3lf\n", sumArr[i][j]);
}
}
}
int
main(int argc, char *argv[])
{
FILE *matrixFile;
int n = atoi(argv[1]); // the number of matrices
printf("Usage: %s <size of nxn matrices>\n", argv[1]);
matrixFile = fopen("/tmp/results.txt", "w+");
if (matrixFile == NULL) {
perror("fopen");
exit(1);
}
double *arrA = malloc(sizeof(double) * n * n);
double *arrB = malloc(sizeof(double) * n * n);
double *sumArr = malloc(sizeof(double) * n * n);
docalc(matrixFile,n,C(arrA),C(arrB),C(sumArr));
if (matrixFile)
fclose(matrixFile);
matrixFile = NULL;
return 0;
}
I just compiled and tested your code. The file name you are giving is incorrect; you need a "/" in front of "home".
Not sure what the requirements are, but write your matrixFile like a matrix: add a new line after each row of the matrix is "multiplied", not after every element:
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
sumArr[i][j] = arrA[i][j] * arrB[i][j];
printf("Writing matrix ");
fprintf(matrixFile, "%0.3lf ", sumArr[i][j]);
}
fprintf(matrixFile, "\n");
}
Also, take Craig Easley's comment seriously. Stack Overflow can happen, even off the premises this website ;) Consider allocating your matrix dynamically on the heap.

Generate int of numbers between 1 and n with dynamic n

I am struggling with an algorithm to print numbers between 1 and a dynamic variable n into an int.
int n = // dynamic value
int i = 0;
int output[n];
for(i = 0; i < n; i++) {
output[i] = i;
}
However, as n is dynamic, the code won't compile.
Any help would be much appreciated - thanks in advance.
You need to allocate a buffer, or dynamic-sized array, with malloc:
int n = // whatever
int i = 0;
int* output = NULL;
// Allocate the buffer
output = malloc(n * sizeof(int));
if (!output) {
fprintf(stderr, "Failed to allocate.\n");
exit(1);
}
// Do the work with the array
for(i = 0; i < n; i++) {
output[i] = i;
}
// Finished with the array
free(output);
output is a pointer to the beginning of the buffer you allocated, and you can treat it as an array of n ints.
When you're finished with the array, you need to de-allocate the memory with free.
This should work:
int n = // whatever
int i = 0;
int* output = (int*)malloc(sizeof(int)*n);
for(i = 0; i < n; i++) {
output[i] = i;
}
Don't forget to free(output); when you don't need it anymore.
EDIT: Made it C.
If 'n' is changing during runtime, then you could use malloc like suggested in the comments. Then check if you need more space, then automatically realloc more space should it be needed

Resources