Sort floating point values from a file (read/write) - c

I am writing a C program that should sort floats (increasingly). The values are saved in a file and then after the sort, the values are saved into the same file. I am using library functions to read and write. I am using radixsort to sort the floats.
This is the code I currently have. Rather than the array being populated with values from the file that I am reading, it is storing 0.000000 for every index. I am not sure where I am going wrong in my implementation.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
void swap(float *a, float *b, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
float tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
void radixSort(float array[], size_t count)
{
int numZeroes=0;
float tempArr1[count];
float * tempArr2 = tempArr1;
for (uint32_t radix=1;radix;radix<<=1){
uint32_t * intArray = (uint32_t *)array;
int count0=0;
int count1=0;
numZeroes=0;
for (int j=0; j<count; ++j)
numZeroes += !(intArray[j]&radix);
count1=numZeroes;
for (int j=0; j < count; ++j)
if (intArray[j]&radix){
tempArr2[count1]=array[j];
++count1;
}
else{
tempArr2[count0]=array[j];
++count0;
}
swap(tempArr2,array,count);
}
if (numZeroes<count){
memcpy( tempArr2+(count-numZeroes), array, numZeroes*sizeof(float));
for (int d=0,j=count-1;j>=numZeroes;j--,d++)
tempArr2[d]=array[j];
memcpy( array, tempArr2, count * sizeof(float));
}
}
int main(int argc, char *argv[]) {
FILE *fd, *writeFile;
int i = 0;
float number;
int elementnum = 0;
struct stat st;
int fd2;
fd=fopen(argv[1], "r");
fd2 = fileno(fd);
if(fd==NULL){
printf("Error opening file\n");
}
fstat(fd2, &st);
off_t size = st.st_size;
for(int j = 0; j < size/4; j++){
elementnum++;
}
float array[elementnum];
while(fscanf(fd, "%f", &number)==1) {
array[i] = number;
i++;
}
radixSort(array,elementnum);
for(int j = 0; j < elementnum; j++){
printf("%f\n", array[j]);
}
fclose(fd);
writeFile=fopen("argv[1]", "w");
for(int j = 0; j < elementnum; j++){
fprintf(writeFile, "%f\n", array[j]);
}
fclose(writeFile);
return 0;
}

At least these issues:
Code is assuming the size of the text file divided by 4 is the number of float. This is risky and error prone. #agus
Instead of fstat(fd2, &st);, count them
size_t elementnum = 0;
while(fscanf(fd, "%f", &number)==1) {
elementnum++;
}
rewind(fd);
float array[elementnum];
for (i=0; i < elementnum; i++) {
if (fscanf(fd, "%f", &number) != 1) {
puts("We have trouble reading the same on the 2nd pass");
exit(1);
}
array[i] = number;
}
radixSort(array, elementnum);
/ 4 might make sense with a binary file and using fread() to read float.
it is storing 0.000000 for every index
Writing float with "%f" is uninformative with small values. Better to use "%e" or "%g".
#include <float.h>
// fprintf(writeFile, "%f\n", array[j]);
fprintf(writeFile, "%g\n", array[j]);
// or better
fprintf(writeFile, "%.*g\n", FLT_DECIMAL_DIG, array[j]);

Related

Problem with scanning many integers in a row

When trying to read about 2000 int numbers, scanf() stops working after 1040 ints. How can I solve this problem?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
int length;
scanf("%d", &length);
int32_t *array = (int32_t *) calloc(length, sizeof(int32_t));
for (int32_t i = 0; i < length; i++) {
scanf("%d", &array[i]);
}
printf("\nAll data are scanned\n");
for (int32_t i = 0; i < length; i++) {
printf("%d, ", array[i]);
}
free(array);
return 0;
}

Loading all text lines into different tables dynamically located in c

Command:
the program reads the file and saves it in memory, treating each line as a subtitle (Note: to simplify the program, we can assume that we know the limit for the length of the line (say 1023 characters) and we know the limit for the number of lines (say 2048), but we expect that the lengths of individual lines can vary greatly, so we allocate the memory for each line dynamically during reading, writing the addresses of subsequent subtitles in the table)
I have a code that reads one line, but I don't know how to change it so that the program reads all the lines into different arrays and then reads the indicators into them into the next array
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1023
#define ROW 32
int main()
{
FILE *fp;
char *array;
size_t csize = ROW;
size_t cpos = 0;
int ch;
fp = fopen("plik.txt", "r");
array = malloc(ROW);
while((ch = fgetc(fp))!='\n'&& ch!='\r')
{
array[cpos++] = ch;
if(cpos == csize)
{
csize += ROW;
array = realloc(array, csize);
}
}
array[cpos] = 0;
fclose(fp);
free(array);
return 0;
}
Here I have example how you can initialize dynamicaly two dimentional array of floats.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
int x, y;
printf("Enter x\n");
scanf("%d", &x);
printf("Enter y\n");
scanf("%d", &y);
float** matrix = (float**)malloc(x * sizeof(float));
for (int i = 0; i < x; i++)
{
matrix[i] = (float*)malloc(y * sizeof(float));
}
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
int value = rand()%10000;
matrix[i][j] = (float)value / 100;
printf("%.2f ", matrix[i][j]);
}
printf("\n");
}
free(matrix);
}
Play a little bit with this code. You shouldn't have any problems to initialize every line with different length.

Read file into multidimensional character array in C

I am trying to read a Multidimensional String Matrix from a file and store it to a array of Character Arrays like this:
char *A[M][N];
This works fine if I stay inside the main function.
But when i am trying to call a function by reference it doesn't work.
Function Call:
readMatrix(file,A);
Function Header:
int readMatrix(FILE *file,char *matrix[][]);
I also tried this:
int readMatrix(FILE *file,char ***matrix);
which also doesn't work.
I want to manipulate the Array in the function therefore i need to make a reference call.
You must pass N as part of the matrix type to your ReadMatrix function, and since it is not known at compile time, you must pass these as arguments too:
int readMatrix(FILE *file, size_t M, size_t N, char *matrix[][N]);
You could indeed also specify the array argument as char *matrix[M][N], but the first dimension size M is ignored for a function argument as it only receives a pointer to the array.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int readMatrix(FILE *file, size_t rows, size_t cols, char *matrix[][cols]) {
int rc = 0;
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
char buf[80];
if (rc == 0 && fscanf(file, "%79s", buf) == 1) {
matrix[i][j] = strdup(buf);
} else {
matrix[i][j] = NULL;
rc = -1;
}
}
}
return rc;
}
int main(void) {
size_t rows, cols;
if (scanf("%zu %zu", &rows, &cols) != 2)
return 1;
char *mat[rows][cols];
if (readMatrix(stdin, rows, cols, mat) == 0) {
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
printf(" %8s", mat[i][j]);
}
printf("\n");
}
}
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
free(mat[i][j]);
}
}
return 0;
}
You can do it by using this approach:
#include <stdio.h>
#define MAX_WORD_SIZE 10
void readMatrix(FILE*,char****);
int main(void){
FILE* cin = fopen("input.txt","r");
char*** inputMatrix;
readMatrix(cin,&inputMatrix);
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
printf("%s ",*(*(inputMatrix+i)+j));
}
printf("\n");
}
fclose(cin);
return 0;
}
void readMatrix(FILE* cin,char**** matrix){
int rowNum,columnNum;
char buff[10];
int intBuff;
fscanf(cin,"%d",&intBuff);
rowNum = intBuff;
fscanf(cin,"%d",&intBuff);
columnNum = intBuff;
*matrix = malloc(rowNum*sizeof(char**));
for(int i=0;i<rowNum;i++){
*(*matrix+i) = malloc(columnNum*sizeof(char*));
}
for(int i=0;i<rowNum;i++){
for(int j=0;j<columnNum;j++){
*(*(*matrix+i)+j) = malloc(MAX_WORD_SIZE*sizeof(char));
fscanf(cin,"%s",*(*(*matrix+i)+j));
}
}
}
with this input file(input.txt file within same folder), this code is working well on Linux GCC
3 3
ab cd ef
gh ij kl
mn op qr
In the first line of input.txt file, first integer denotes row number, second integer denotes column number.

Ordering floats read from file with quick select give segmentation fault

I have to use quick select to sort and write the first N elements of an array and write them on a text.
The problem is with the input file and the quantity of data I try to read from it.
I use a constant, N, to define the max quantity of number I want to read from the file, but so far it only reads and sorts up to 194 elements from the file. I should be able to do it with 10 million, however.
Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#define N 194
float qselect(float *array,int ini, int fin, int k){
int i;
int st = ini;
float tmp;
//finding a pivot
for (i = 0; i < fin - 1; i++) {
if (array[i] < array[fin-1]) {
tmp = array[st];
array[st] = array[i];
array[i] = tmp;
st++;
}
}
//exchanging the pivot with the last element of the array
tmp = array[fin-1];
array[fin-1] = array[st];
array[st] = tmp;
//veryfing the pivot
if (k == st)
return array[st];
else if (st>k)
return qselect(array,ini,st,k);//search on the left
else
return qselect(array,ini+st,fin,k);//search on the right
}
int main(void)
{
FILE *input;
FILE *output;
int range;
//opening the files
input = fopen("numeros.txt","r");
output = fopen("out.txt","w");
printf("Select your N : ");
scanf("%d",&range);
float *array_x;
array_x = malloc(sizeof(float)*N);
float num;
int size=0;
for(int f=0;f<N; f++){
fscanf(input,"%f",&array_x[size]);
size++;
}
int i;
for (i = 0; i < range; i++) {
fprintf(output,"%f ", qselect(array_x,0, size, i));
}
fclose(input);
fclose(output);
free(array_x);
return 0;
}
If I try to define N=195 or more, the code doesn't work.

Sorting vectors based on length in C

I want to make a programm that takes the dimension and numbers of vectors to be sorted based on their length.
Most of the code works but the sort part of the program doesnt.
Basically what I want to do there is: compare the output from the bereken_lengte function from 2 places in the array w. But nothing seems to happen.
Also in the function bereken_lengte, I cant take the roots of the sum after the loop ended.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double bereken_lengte(double *array, int dim)
{
int i, j;
double sum = 0.0;
for(i=0; i<dim; ++i)
sum += pow(array[i],2);
return sum;
}
void swap(double **p, double **q)
{
double *tmp;
tmp = *p;
*p = *q;
*q = tmp;
}
void sort_vector(double *w[] , int num , int dik )
{
int i,dim,j;
dim = dik;
for(i=0;i<num;++i)
for(j = 1+i;j<num;++j)
{
if(bereken_lengte(w[i],dim) > bereken_lengte(w[j],dim) )
swap(&w[i], &w[j]);
}
}
int main (void)
{
int dim, num;
int i, j,k,l;
double **w;
scanf ("%d %d", &dim, &num); /* read N and M */
w = calloc (num, sizeof (double *)); /* allocate array of M pointers */
for (i = 0; i < num; i++)
{
/* allocate space for N dimensional vector */
w[i] = calloc (dim, sizeof (double));
/* read the vector */
for (j = 0; j < dim; j++)
{
scanf ("%lf", &w[i][j]);
}
}
sort_vector(w,num,dim);
for(k=0; k<num; ++k)
{
printf("\n");
for(l=0; l<dim; ++l)
printf("%f ", w[k][l]);
}
return 0;
}
double bereken_lengte(double *array, int dim)
{
unsigned int i;
double sum =0.0;
for(i=0; i<dim; ++i)
sum += pow(array[i],2);
return sum;
}
Just initialise the sum to zero before summing.
BTW I changed i to unsigned. It is IMnsvHO a good habit to use unsigned types for index && size variables (they won't underflow, and if the do, you'll notice it)
UPDATE:
This tries to avoid the int indices and sized, and uses qsort. (rather ugly, because the compare function takes only two elements; don't try this in a multithreaded program ...) Note, I may have rows and columns interchanged, but thats a way of life... gewoon, omdat het kan!:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double bereken_lengte(double *array, size_t dim)
{
size_t i;
double sum=0.0;
for(i=0; i<dim; ++i)
sum += pow(array[i],2);
return sum;
}
/* this is ugly: qsort only allows only two arguments */
static size_t ze_third_argument=0;
int srt_pdbl(void *l, void *r)
{
double **dl = l, **dr = r;
double diff;
diff = bereken_lengte( *dl, ze_third_argument) - bereken_lengte( *dr, ze_third_argument) ;
return (int) diff;
}
void sort_vector(double *w[] , size_t num , size_t dik )
{
ze_third_argument = dik;
qsort(w, num, sizeof *w, srt_pdbl );
}
int main (void)
{
size_t dim, num;
size_t i, j,k,l;
double **w;
scanf ("%zu %zu", &dim, &num); /* read N and M */
w = calloc (num, sizeof *w); /* allocate array of M pointers */
for (i = 0; i < num; i++)
{
/* allocate space for N dimensional vector */
w[i] = calloc (dim, sizeof *w[i] );
/* read the vector */
for (j = 0; j < dim; j++)
{
scanf ("%lf", &w[i][j]);
}
}
sort_vector(w,num,dim);
for(k=0; k<num; ++k)
{
printf("\n");
for(l=0; l<dim; ++l)
printf("%f ", w[k][l]);
}
return 0;
}

Resources