How to use more than one dynamic allocation on C programming? - c

I'm making a program that reads two sets of data (float) from two different .txt files, and then it transfers these data to two different arrays, which will be used in further calculations. However, when I try to use dynamic allocation more than once, something goes wrong and the data seem not to be stored in the array.
The following simplified program seems to be working fine:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
float *VarA;
int n = 0;
int *counter;
int i;
FILE *input1;
input1 = fopen("C:\\Users\\...test.txt","r");
VarA = (float*)calloc(20001, sizeof(float));
for(i = 0; i < 20001; i++)
{
fscanf(input1,"%f",&VarA[i]);
printf("%f\n",VarA[i]);
}
free(VarA);
fclose(input1);
return 0;
}
it successfully shows the data stored in the array VarA. However, if I introduce a new array to count the number of lines in the file (which is necessary for my further calculations), I just get the value 0.000000 from every array element:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
float *VarA;
int n = 0;
int *counter;
int i;
FILE *input1;
input1 = fopen("C:\\Users\\...test.txt","r");
counter = (int*)calloc(100000, sizeof(int));
while(fscanf(input1,"%f",&counter[n]) != EOF)
{
n++;
}
free(counter);
printf("n = %i\n", n);
VarA = (float*)calloc(n, sizeof(float));
for(i = 0; i < n; i++)
{
fscanf(input1,"%f",&VarA[i]);
printf("%f\n",VarA[i]);
}
free(VarA);
fclose(input1);
return 0;
}
I know that I can avoid using another array to count the number of lines. The point is that every time I use another array, for any purpose, I get the same result. For instance, if I don't use an array to count the number of lines, but I make another one to store my other set of data, one of these arrays just won't present the data after the reading. I tried to modify my program several times in order to find the source of such behavior, but without success.

(At least) two major problems: first,
counter = (int*)calloc(100000, sizeof(int));
while(fscanf(input1,"%f",&counter[n]) != EOF) {
n++;
}
free(counter);
is basically saying "Grab me a chunk of memory, fill it with data as I read the file, then throw it away without ever using it." Probably not what you intended. Then,
VarA = (float*)calloc(n, sizeof(float));
for (i = 0; i < n; i++) {
fscanf(input1,"%f",&VarA[n]);
printf("%f\n",VarA[n]);
}
free(VarA);
which says, "Grab a big chunk of memory, then read data from after the end of the file I just read everything from, put it there, then throw it away."
If you want to read the data from the same file again, you'll have to close it an reopen it (or "seek" to the start). And if you want to do anything with it, you'll have to do it before free()ing the memory you loaded it into.

counter = (int*)calloc(100000, sizeof(int));
// ^--- `int*` ^--- `int`
// v--- `int` pointer
while(fscanf(input1,"%f",&counter[n]) != EOF)
// ^--- `float` designator
Do you see any discrepancies here? Your code allocates ints, then passes a pointer to those ints to fscanf telling it they're floats (using the %f designator). According to the C standard draft n1570, section 7.21.6.2p10 this constitutes undefined behaviour:
If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
My suggestion would be to use the * assignment suppression modifier here, for example:
while (fscanf(input1, "%*f") != EOF) n++;
or, alternatively
while (fscanf(input1, "%f", &(float){0}) != 1) n++;
Note also how I've changed the check from EOF to 1. You can find more information about the return values of fscanf here (which you really should read before using any scanf-related function... and stop guessing, because guessing in C can be harmful).
Additionally, you need to rewind your file once it reaches EOF, otherwise every call to fscanf following this loop will return EOF:
rewind(input1);
P.S. Don't cast malloc in C. This goes for calloc and realloc, too. There's a lot of this quoted stuff that has opengroup manuals of its own; I'll leave it as an exercise to you to find (and read) the opengroup manuals.

Related

How to reduce the reserved memory that is not currently being used in an array in C?

Let's say we reserved 32 bytes for an array in C, but it turns out we are only using 24 bytes, how can I reduce the reserved memory that is not currently in use? Is this even possible?
I am not using malloc, but I could.
This is the working minimal reproducible example:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
FILE *input;
input = fopen("1.txt", "r");
int arr[4][300];
if (input == NULL) {
printf( "ERROR. Coundn't open the file.\n" ) ;
} else {
for (int i = 0; i < 300; i++) {
fscanf(input, "%d %d %d %d", &arr[0][i], &arr[1][i],
&arr[2][i], &arr[3][i]);
}
fclose(input);
int sze = 0;
for (int i = 0; i < 300; i++) {
for (int j = 0; j < 4; j++) {
if (abs(arr[j][i]) >= 1)
sze += log10(abs(arr[j][i])) + 1;
else
sze++;
if (arr[j][i] < 0)
sze++;
}
}
printf("Size %d kB\n", sze);
}
return 0;
}
Clarification: What I need is to reduce the memory used by each element in the array, if possible. Let's say I have the number 45 stored, it doesn't take up all 4 bytes of an int, so I need to reduce the memory allocated to only 1 byte. As I said, I am not currently using malloc, but I could switch to malloc, if there's a way to what I want to.
If you want to reduce the used space for a value, you need to assign it to an object of different type.
In your example, you start with an int that probably uses 4 bytes on your system. Then you store the value "45" in it, which needs just one byte. Types with size of 1 byte are for example int8_t or signed char.
First, you cannot change the type of a variable, once it is defined. You may store it in another variable.
Second, all elements of an array have to be of the same type.
So the answer for the given example is simply "No."
If you want to "compress" the stored values, you need to roll your own type. You can invent some kind of "vector" that stores each value in as few bytes as necessary. You will need to store the size of each value, too. And you will need to implement access function to each vector element. This is not a simple task.

function declaration and call and definition in c

Why is this code not running after printing of array if I take value of n>=9?
#include <stdio.h>
#include <math.h>
float mean_function(float array[],int n);
int main() {
int i,n;
float array[n],mean,sum=0,s2,summation,deno,C[i],elements;
printf("Enter No of Elements\n");
scanf("%d",&n);
printf("Enter Elements\n");
for(i=0;i<n;i++){
scanf("%f",&array[i]);
printf("%f",array[i]);
}
printf("sample variance(s2) : (sum((x-mean)*(x-mean)))/(n-1) /n");
printf("population variance(sigma2) : (sum((x-u)*(x-u))/n");
mean_function(array,n);
for(i=0;i<n;i++) {
deno=((array[i]-mean)*(array[i]-mean));
C[i]=deno;
summation=summation+C[i];
}
s2=((summation)/(n-1));
printf("s2=%f \n",s2);
}
float mean_function(float array[],int n) {
int i;
float sum=0,mean;
for(i=0;i<n;i++){ sum=sum+array[i]; }
mean=(sum/n);
return mean;
}
Why is this code not running after printing of array if I take value
of n>=9?
Some thoughts about your code (and about building programs in steps):
Arrays in C don't change in size once defined. VLAs are out for a variety of reasons. malloc() is in.
Use double, unless there is a specific reason to use floats.
Define and initialize one variable per line. Uninit vars can only result in an error as mentioned by #Jens.
Function declarations at the top (which you have done)
During development, there is no need to complicate things with a scanf (at least initially). It only adds an unwarranted layer of complexity. If you are testing statistical functions (mean, variance), put numbers in a pre-defined static array and verify functionality first.
C[i] as been declared with uninitialized i.
For this initial phase of building this program, I include a basic program.
I am not a fan of zero space between tokens (but ignore that)
Consider calling your array something other than 'array'.
Calculating the size of the samples array allows you to change the number of elements without changing anything else in code; which adds another layer of complexity to an already difficult phase.
#include <stdio.h>
#include <math.h>
double sample_mean(double* p, int n);
int main()
{
double samples[] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 16.5, 2.3};
double mean = 0.0;
int size_samples = sizeof samples/sizeof(double);
printf("size_samples = %d\n", size_samples);
mean = sample_mean(samples, size_samples);
printf("Mean = %.2lf", mean);
}
// -------------------------------
double sample_mean(double* p, int n)
{
double mean = 0.0;
double total = 0.0;
for(int i = 0; i < n; i++)
total += *p++;
mean = total/n;
return mean;
}
Once this functionality is present (saved), you can start working on other stat functions. This way you can work step by step to get closer to the desired outcome.
Next up you can define sample_variance(double* p, int n) and work on that knowing that additional(new errors) are not coming from your code written so far.
Output:
size_samples = 8
Mean = 5.24
I hope it helps.
The code is likely not running because array[n] is declared with an uninitialized n. At the time you read n with scanf(), the array does not automatically "grow into the right size". You should either declare array big enough, or if you really want it to be user-defined, use malloc to allocate it (read the comp.lang.c FAQ) and all Stackoverflow questions tagged array...)
In addition, the scanf at some point fails. Note that when you enter numbers, you also have the "Enter" as a newline ('\n') in the input stream. You never read the newline so the next scanf fails.
This becomes obvious when you actually check the return value from scanf with code like this:
if (scanf("%f", &array[i]) == 1) {
/* successfully converted 1 item */
}
else {
/* scanf failed */
}
Usually what you want is to skip whitespace in the input. You do this by placing a space in the scanf format. Note that a single space tells scanf to skip any amount of white-space.
if (scanf(" %f", &array[i]) == 1) {

Why does c print a different array the second time it's printed?

My cousin has a school project and we can't figure out why is the array different the second time it's printed when there is no values changing in between?
Basically you enter a number which states how many rows/columns will the matrix have, and during first loop he assigns a number to every position and prints out the random number. However, the second time we go through the matrix the numbers are different and it seems that they are copied through the matrix from bottom left corner to top right corner for some reason. It seems strange to us because we never assign a different value to a position in the array after defining it for the first time.
int i,j,n,matrica[i][j],suma=0;
srand(time(NULL));
printf("\nunesi prirodan broj N[3,20] = \n");
scanf("%d",&n);
for(i=0;i<n;i++) {
for(j=0;j<n;j++) {
matrica[i][j]=rand()%100;
printf("%d, %d = %4d ",i, j, matrica[i][j]);
if(j==n-1) {
printf("\n");
}
}
}
printf("\n");
for(i=0;i<n;i++) {
for(j=0;j<n;j++) {
printf("%d, %d = %4d ", i, j, matrica[i][j]);
if(j==n-1) {
printf("\n");
}
}
}
And here is the result of this (the code I pasted here has 2 prints, and in the image there is 3 but every time you go through the matrix after the first time it's going to be the same):
We need to use malloc to allocate the dynamic amount of memory.
After
scanf("%d",&n) // PS You should check the return value - read the manual page
Put
matrica = malloc(sizeof(int) * n * n);
And declare it as
int *matrica;
Then replace
matrica[i][j]
with
matrica[i * n + j]
And after you have finished with matrica - use free i.e.
free(matrica);
int i,j,n,matrica[i][j]
At this point I must ask, what value do you think i and j will have? Right there you're invoking undefined behaviour by referring to variables declared with automatic storage duration which you've not initialised. Anything after this point is... undefined behaviour.
Having said that, I noticed a few other parts that look strange. Which book are you reading? The reason I ask is that the people I know to be reading reputable textbooks don't have these problems, thus your textbook (or resource, whatever) mustn't be working for you...
I can't read the commentary inside of the string literals, which is a shame, since that's usually quite valuable contextual information to have in a question. Nonetheless, moving on, if this were me, I'd probably declare a pointer to an array n of int, after asking for n, like so:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t n;
printf("Enter n, please: ");
fflush(stdout);
if (scanf("%zu", &n) != 1 || n == 0 || SIZE_MAX / n < n) {
puts("Invalid input or arithmetic overflow...");
return -1;
}
int (*array)[n] = malloc(n * sizeof *array);
if (!array) {
puts("Allocation error...");
return -1;
}
/* now you can use array[0..(n-1)][0..(n-1)] as you might expect */
free(array);
}
This should work for quite high numbers, much higher than int array[n][n]; would in its place... and it gives you that option to tell the user it was an "Allocation error...", rather than just SIGSEGV, SIGILL, SIGBUS or something...
... but nothing would be more optimal than just saving the seed you use to generate the random numbers, and the user input; that's only two integers, no need for dynamic allocation. There's no point storing what rand generates, amd you realise this, right? rand can generate that output purely using register storage, the fastest memory commonly available in our processors. You won't beat it with arrays, not meaningfully, and not... just not.

How do you read values from a text file and store them in 2 different arrays?

The text file contains 52 lines that are in the format:
A .013420
B .000191
C .011222
...
I want to ignore the letters and I need to extract the values from the file and store the first 26 in one array which I named freqOne[] and store the last 26 values in another array named freqTwo[]. I will later use these values for calculations.
here is my attempt:
#include <stdio.h>
#include <stdlib.h>
int main (){
FILE *input1;
/*char freqOne[26]; i use these arrays for attempt 1
char freqTwo[26];*/
double freqOne[26];
double freqTwo[26];
input1 = fopen("test8.txt", "r");
if(input1 == NULL){
perror("test8.txt");
exit(EXIT_FAILURE);
}
/* attempt one: all the values print out correctly but idk how to use them :(*/
/*while(fgets(freqOne, sizeof(freqOne), input1)){
printf("%s", freqOne);
}
while(fgets(freqTwo, sizeof(freqTwo), input1)){
printf("%s", freqTwo);
}
*/
/*fclose(input1); */
int h;
int i;
/* another attempt i made, this one prints out the a large negative number for every element :(*/
for(i=0; i<26; i++){
fscanf(input1,"%lf", &freqOne[i]);
printf("%lf\n", freqOne[i]);
}
for(h=0;h<26; h++){
fscanf(input1,"%lf", &freqTwo[h]);
printf("%lf\n", freqTwo[h]);
}
fclose(input1);
/*a = (freqOne[0]-freqTwo[0])*(freqOne[0]-freqTwo[0]);
printf("%lf", a);*/
}
In my first attempt, i was able to print out all the values correctly, but I am not sure how to use them. I printed them out as strings, but when I try to print them out as %lf, it gave me 0's for every value.
In my second attempt, I did some googling and found that I should try the fscanf function, but this did not work for either and a large negative number was printed out for every value. I am pretty stuck right now and out of ideas.
So OP can close this post:
To ignore the A,B,C, etc., use assignment suppression '*'
// fscanf(input1,"%lf", &freqOne[i]);
fscanf(input1,"%*s %lf", &freqOne[i]);
Always a good idea to check I/O function results:
if (fscanf(input1,"%*s %lf", &freqOne[i]) != 1) Handle_Unexpected_Input();

Alphabetically Ordering an array of words

I'm studying C on my own in preparation for my upcoming semester of school and was wondering what I was doing wrong with my code so far.
If Things look weird it is because this is part of a much bigger grab bag of sorting functions I'm creating to get a sense of how to sort numbers,letters,arrays,and the like! I'm basically having some troubles with the manipulation of strings in C currently.
Also, I'm quite limited in my knowledge of C at the moment!
My main Consists of this:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
int numbers[10];
int size;
int main(void){
setvbuf(stdout,NULL,_IONBF,0); //This is magical code that allows me to input.
int wordNumber;
int lengthOfWord = 50;
printf("How many words do you want to enter: ");
scanf("%i", &wordNumber);
printf("%i\n",wordNumber);
char words[wordNumber][lengthOfWord];
printf("Enter %i words:",wordNumber);
int i;
for(i=0;i<wordNumber+1;i++){ //+1 is because my words[0] is blank.
fgets(&words[i], 50, stdin);
}
for(i=1;i<wordNumber+1;i++){ // Same as the above comment!
printf("%s", words[i]); //prints my words out!
}
alphabetize(words,wordNumber); //I want to sort these arrays with this function.
}
My sorting "method" I am trying to construct is below! This function is seriously flawed, but I'd thought I'd keep it all to show you where my mind was headed when writing this.
void alphabetize(char a[][],int size){ // This wont fly.
size = size+1;
int wordNumber;
int lengthOfWord;
char sortedWords[wordNumber][lengthOfWord]; //In effort for the for loop
int i;
int j;
for(i=1;i<size;i++){ //My effort to copy over this array for manipulation
for(j=1;j<size;j++){
sortedWords[i][j] = a[i][j];
}
}
//This should be kinda what I want when ordering words alphabetically, right?
for(i=1;i<size;i++){
for(j=2;j<size;j++){
if(strcmp(sortedWords[i],sortedWords[j]) > 0){
char* temp = sortedWords[i];
sortedWords[i] = sortedWords[j];
sortedWords[j] = temp;
}
}
}
for(i=1;i<size;i++){
printf("%s, ",sortedWords[i]);
}
}
I guess I also have another question as well...
When I use fgets() it's doing this thing where I get a null word for the first spot of the array. I have had other issues recently trying to scanf() char[] in certain ways specifically spacing my input word variables which "magically" gets rid of the first null space before the character. An example of this is using scanf() to write "Hello" and getting " Hello" or " ""Hello"...
Appreciate any thoughts on this, I've got all summer to study up so this doesn't need to be answered with haste! Also, thank you stack overflow as a whole for being so helpful in the past. This may be my first post, but I have been a frequent visitor for the past couple of years and it's been one of the best places for helpful advice/tips.
You're going to like this - it's a derivation of QSort, adapted to your situation. It may not work quite perfectly for you without a touchup here or there (TEST FIRST!):
void qsort (Strings[], NumberOfItems)
{
char Temp[51]; // Assumes your max string length of 50
int I1 = 0; // Primary index
int I2 = 0; // Index + 1
int NumberOfItems_1 = 0;
bool Swapped = false;
do // Outer loop
{
Swapped = false;
// Decrement our limit
NumberOfItems--;
// Save time not performing this subtraction many times
NumberOfItems_1 = NumberOfItems - 1;
// Repeatedly scan the list
for (I1 = 0; I1 < NumberOfItems_1; I1++)
{
// Save time not performing this addition many times
// I1 points to the current string
// This points to the next string
I2 = I1 + 1;
// If the current string is greater than the next string in the list,
// swap the two strings
if (strcmp(Strings[I1], Strings[I2]) > 0)
{
strcpy (Temp, Strings[I1]);
strcpy (Strings[I1], Strings[I2]);
strcpy (Strings[I2], Temp);
Swapped = true;
}
}
}
while (Swapped); // Break out when we've got nothing left to swap
}
I see a few things wrong with your code off the bat. First, you declare sortedWords as a multidimensional array (since you have sortedWords[wordnumber][lengthofword], but you try to use it with only one index later on.. this doesn't work! Also, your passing of the 2D array is not valid. Check out this post to see the valid ways to pass a 2D array: Passing a 2D array to a C++ function
Function declaration and definition
The function declaration is invalid, as you've found out. You must specify the size of every dimension of the array except the first, so you might write:
void alphabetize(char a[][SOMESIZE], int size)
However, you have a non-constant second dimension (so you're using a VLA or variable length array), which means that you need to pass both sizes to the function, and pass them before you pass the array:
void alphabetize(int size, int length, char a[size][length])
and then invoke it:
alphabetize(wordNumber, lengthOfWords, words);
Of course, you should also declare the function before you try calling it.
There are probably other issues to be addressed, but this is the immediate one that jumps out. For example, you need to use size and length to control the loops in the function. You probably don't need to copy the data into the local array (in which case you don't need the local array). Etc.
You should consider compiling with options such as:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Wold-style-declaration -Werror …
Note that note all versions of GCC support all those options, but use as many as are supported.
Input issue
You have:
int i;
for (i = 0; i < wordNumber + 1; i++) { //+1 is because my words[0] is blank.
fgets(&words[i], 50, stdin);
}
You're stepping out of bounds of your array, which potentially wreaks havoc on your code. The first entry is blank because scanf() leaves the newline in the input buffer. You should read to the end of line before going to line-based input:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
You should also check the fgets() returns a non-null pointer; don't continue if it does.

Resources