Dynamic Memory Allocation to Reverse Print Array of Floating Point Numbers - c

So I'm brand new to C and playing around with memory allocation for arrays. I'm trying to create a program that will dynamically allocate space using malloc to reverse an array of floating point numbers.
#include <stdio.h>
#include <stdlib.h>
struct Rec {
float * x;
int size;
};
int main(){
struct Rec a[50];
int i, y;
printf("Enter the number of floating point numbers: ");
scanf("%d", &y);
x = malloc(y * sizeof(struct));
printf("Enter 5 floating point numbers: \n");
for(i = 0; i < sizeof(struct); i++){
scanf("%.3f", &x[i]);
}
printf("The numbers in reverse order are: \n");
for(i = --sizeof(struct); i >= 0; i--){
printf("%f \n", a[i]);
}
}
During compilation, the following errors are generated:
error: use of undeclared identifier 'x'
*x = malloc(y * sizeof(struct);
^
test.c:14:25: error: declaration of anonymous struct must be
a definition
*x = malloc(y * sizeof(struct);
^
test.c:14:32: error: type name requires a specifier or qualifier
*x = malloc(y * sizeof(struct);
^
test.c:14:31: error: type name requires a specifier or qualifier
x = malloc(y * sizeof(struct));
^
test.c:14:24: note: to match this '('
*x = malloc(y * sizeof(struct);
^
test.c:25:3: error: expected '}'
}
^
test.c:9:11: note: to match this '{'
int main(){
^

Your pointer x is part of the structure which is stored in an array. You probably want to access your "x" through the structure. So instead of
x = malloc(y * sizeof(struct));
You probalby want
a[some index].x = malloc(y * sizeof(struct));
This above line will compile but will most likely give you incorrect results. Since you want to allocate it, you want it to be the size of the variable that you are planning to store there, not the size of the struct.
I should mention that there are other problems. You can't iterate through a structure that way. You want to instead iterate over the length of the array (of structs) instead.

There are a lot of issues with your code. I would advise you to practice more with C basics before attempting to do this. Here is approximation of what you might have wanted to achieve with your code:
#include <stdio.h>
#include <string.h>
// This structure can hold array of floats - and their size
struct Rec
{
float * x;
int size;
};
int main()
{
// Declare variable of type rec
struct Rec a;
int i, y;
// How many floats to store? This could also be stored in a.size instead of y
printf("Enter the number of floating point numbers: ");
scanf("%d", &y);
// Create and populate dynamic array
a.x = malloc(y * sizeof(float));
printf("Enter floating point numbers: \n");
for(i = 0; i < y; i++)
{
scanf("%.3f", &a.x[i]);
}
// Print
printf("The numbers in reverse order are: \n");
for(i = y-1; i >= 0; i--)
{
printf("%f \n", a.x[i]);
}
free(a.x);
return 0;
}

Related

Given an array of structs, how to pass all the values for one member of the struct to a function

Given an array of structs, is there a way to pass
emp[0].hourly_wage, emp[1].hourly_wage, emp[2].hourly_wage, emp[3].hourly_wage, emp[4].hourly_wage
to a function as an array of floats?
Is it possible to pass an array of floats containing only the "hourly_wage" member and not the "OT" member... without just copying the values into a separate array of floats and then passing it to the function.
struct employee
{
float hourly_wage;
float OT;
};
struct employee emp[5];
No, you cannot but you can create another array of pointers pointing to that one member in the array of structure and pass this array of pointers to function.
Implementation:
#include <stdio.h>
#define ARR_SZ 5
struct employee
{
float hourly_wage;
float OT;
};
void test_fun(float **arr) {
for (int i = 0; i < ARR_SZ; ++i) {
printf ("%f ", *arr[i]);
}
printf ("\n");
}
int main(void) {
struct employee emp[ARR_SZ];
for (int i = 0; i < ARR_SZ; ++i) {
emp[i].hourly_wage = 2.0f; // dummy value
emp[i].OT = 1.0f; // dummy value
}
float *hw_arr[ARR_SZ];
for (int i = 0; i < ARR_SZ; ++i) {
hw_arr[i] = &(emp[i].hourly_wage);
}
test_fun(hw_arr);
return 0;
}
Or simply pass the array of structure to the function and access that member:
#include <stdio.h>
#define ARR_SZ 5
struct employee
{
float hourly_wage;
float OT;
};
void test_fun(struct employee *arr) {
for (int i = 0; i < ARR_SZ; ++i) {
printf ("%f ", arr[i].hourly_wage);
}
printf ("\n");
}
int main(void) {
struct employee emp[ARR_SZ];
for (int i = 0; i < ARR_SZ; ++i) {
emp[i].hourly_wage = 2.0f; // dummy value
emp[i].OT = 1.0f; // dummy value
}
test_fun(emp);
return 0;
}
No.
The closest might be:
float a[10];
memcpy(a, emp, sizeof(a));
Or:
void foo(float *a) { ... }
foo((float *) emp);
But that is probably undefined behaviour as it relies on there being no packing at the end of each struct (probably none in this case, but not universally true - see the answers here), and anyway gives the data in the wrong order for you.
It's no possible.
An array requires that the array elements are located in consecutive memory (note: there may be padding between members but that's not relevant here).
In your case the memory layout of emp is like:
addrX (i.e. emp) : float // emp[0].hourly_wage
addrX + 1 * sizeof(float): float // emp[0].OT
addrX + 2 * sizeof(float): float // emp[1].hourly_wage
addrX + 3 * sizeof(float): float // emp[1].OT
addrX + 4 * sizeof(float): float // emp[2].hourly_wage
addrX + 5 * sizeof(float): float // emp[2].OT
...
and there is no way to turn that into
addrY : float // emp[0].hourly_wage
addrY + 1 * sizeof(float): float // emp[1].hourly_wage
addrY + 2 * sizeof(float): float // emp[2].hourly_wage
...
without copying from the first array to another array.
Instead the normal thing to do, is to pass the whole array of struct, i.e. pass a struct employee pointer and access whatever you need from the struct.

A basic question trying to make a structure

What I'm trying to do is get student's name and score in three subjects in the form of a structure array and print their name and average score.
Where is my mistake?
#include <stdio.h>
typedef struct
{
char name[5];
int Kor; //yeah the three subjects
int Eng;
int Math;
}data;
double avg(int a, int b, int c) //to get the average
{
double m;
m = (a + b + c) / 3;
return m;
}
int main()
{
data group[3];
for (int i = 0; i < 3; i++)
{
scanf("%s %d %d %d", group[i].name, group[i].Kor, group[i].Eng, group[i].Math);
}
for (int j = 0; j < 3; j++)
{
printf("%s %lf\n", group[j].name, avg(group[j].Kor, group[j].Eng, group[j].Math));
}
return 0;
}
One thing you should make sure and do is compile with most/all compiler warning flags on. In your case, when I compiled your program with GCC, using the flags -W -Wall -Wextra, I got the following warnings:
<source>: In function 'main':
<source>:23:20: warning: format '%d' expects argument of type 'int *', but argument 3 has type 'int' [-Wformat=]
23 | scanf("%s %d %d %d", group[i].name, group[i].Kor, group[i].Eng, group[i].Math);
| ~^ ~~~~~~~~~~~~
| | |
| int * int
and the same warning for group[i].Eng and group[i].Math.
These compiler warnings are very often actually errors of yours, which, at runtime, will result in the program crashing or producing garbage. In your case, you need to pass the address of the value you want to read from the input.
This does not mean that's the only issue with your code, but you should really let the compiler help you before asking us for help.
I change the scanf, '&' operator is used to access to the address in the memory location. scanf("%d",&a) means that the value entered from the keyboard must be stored in the memory LOCATION where which is given the name 'a'.
and change the calculating function of the average because you are using the integer division version of operator/, which takes 2 ints and returns an int. In order to use the double version, which returns a double, at least one of the ints must be casted to a double.
#include <stdio.h>
typedef struct
{
char name[5];
int Kor; //yeah the three subjects
int Eng;
int Math;
}data;
double avg(int a, int b, int c) //to get the average
{
double m;
m = (a + b + c) / 3.0;
return m;
}
int main()
{
data group[3];
for (int i = 0; i < 3; i++)
{
printf("enter your name ,Kor grade ,Eng grade ,Math grade\n");
scanf("%s %d %d %d", group[i].name, &group[i].Kor, &group[i].Eng, &group[i].Math);
}
for (int j = 0; j < 3; j++)
{
printf("name:%s avg:%lf\n", group[j].name, avg(group[j].Kor, group[j].Eng, group[j].Math));
}
return 0;
}

How do I print this array after calling a function upon it?

The following code block is only part of a larger one. In the program, I want to find the definite integral of a polynomial that needs to be inputted by the user.
I'm new to C and so I'm having a hard time trying to learn the syntax with regards to pointers. I find them very confusing.
So if you'll look at the code block below, I want to print the elements contained in the array coefficients just so I can see if the elements inputted are being stored in the array but to no avail. The program just terminates after the inputCoeffs() function.
#include <stdio.h>
#include <stdlib.h>
void inputDegree(int *deg) {
printf("Enter the degree of the polynomial: \n");
scanf("%d", *&deg);
}
void inputCoeffs(int deg, double *coeffs) {
printf("Enter the coefficients of the polynomial (A, B, C,...): \n");
for(int i = 0; i <= deg; i++) {
scanf("%lf", &coeffs[i]);
}
}
int main() {
int i;
int degree;
double lowerLimit;
double upperLimit;
double integral;
double *coefficients = NULL;
double *integralCoefficients = NULL;
inputDegree(&degree);
coefficients = (double*)malloc((degree + 1) * sizeof(double));
integralCoefficients = (double*)malloc((degree + 1) * sizeof(double));
inputCoeffs(degree, &coefficients);
for(i = 0; i <= degree; i++) {
printf("\t%lf\n", coefficients[i]);
}
return 0;
}
In this call
scanf("%d", *&deg);
it is enough to write
scanf("%d", deg);
It is unclear why you are allocating memory one element greater than the value of degree.
coefficients = (double*)malloc((degree + 1) * sizeof(double));
In this case the allocated array has degree + 1 elements.
The type of the second argument in this call
inputCoeffs(degree, &coefficients);
is invalid. There shall be
inputCoeffs(degree, coefficients);
The & operator is used to get a pointer to an existing variable, while * is used to dereference a pointer. Therefore
inputCoeffs(degree, &coefficients);
Makes no sense, because coefficients is already a pointer. inputCoeffs
accepts a pointer so you can just write
inputCoeffs(degree, coefficients);
Since the & and * operators basically do the opposite, this line
scanf("%d", *&deg);
is not an error, but could also just be written as
scanf("%d", deg);
Also, you should call free when ever you use malloc, so add to the end of the code:
free(coefficients);
free(integralCoefficients);

Getting C error "assignment to expression with array type"

The goal of the exercise is to calculate a complex number Z according to some formula and create an array of n such complex numbers. Here's the function that calculates Z
double complex convert(double R, int p)
{
double complex Z=0+0*I;
double complex A, B, C;
A=exp(M_PI/4) + 0*I;
B=cos(11*M_PI/6 + 2*p*M_PI) + 0*I;
C=I*sin(R*M_PI/6);
Z=A*((R*B)+C);
return Z;
}
The function that creates the array:
double complex *array_function (double *a, int n)
{
int i;
double complex array[100];
for (i=0; i<n; i++)
{
array[i]=convert(*(a+i),i);
}
return array;
}
And int main:
int main()
{
int N, i;
double complex *new_array[100];
double array[100];
printf("Enter the length of the array = ");
scanf("%d", &N);
for (i=0; i<N; i++)
{
printf("Element number %d is: ", i+1);
scanf("%f", &array[i]);
}
new_array=array_function(array, N); // where I get the error message
printf("The new array is: \n");
for (i=0; i<N; i++)
{
printf("%f + i%f \n", creal(new_array[i]), cimag(new_array[i]));
}
return 0;
}
But I keep getting the same error message: "assignment to expression with array type" in regards to the line: "new_array=array_function(array, N);"
Edit: Here's the edited code:
double complex convert(double R, int p)
{
double complex Z=0+0*I;
double complex A, B, C;
A=exp(M_PI/4) + 0*I;
B=cos(11*M_PI/6 + 2*p*M_PI) + 0*I;
C=I*sin(R*M_PI/6);
Z=A*((R*B)+C);
return Z;
}
double complex *array_function (double *a, int n)
{
int i;
double complex *array = malloc(100 * sizeof *array);
for (i=0; i<n; i++)
{
array[i]=convert(*(a+i),i);
}
return array;
}
int main()
{
int N, i;
double complex *new_array;
double array[100];
printf("Enter the length of the array = ");
scanf("%d", &N);
for (i=0; i<N; i++)
{
printf("Element number %d is: ", i+1);
scanf("%f", &array[i]);
}
new_array=array_function(array, N); // where I get the error message
printf("The new array is: \n");
for (i=0; i<N; i++)
{
printf("%f + i%f \n", creal(new_array[i]), cimag(new_array[i]));
}
return 0;
}
You cannot assign to arrays in C. You can only assign to array elements.
If you want to change arrays dynamically, declare a pointer of the appropriate type and assign the result of malloc and/or realloc.
If you have made the changes to insure you are reading doubles with scanf by adding the 'l' modifier to your %f format specifier (e.g. "%lf") and you have fixed your attempt to return a statically declared array, by declaring a pointer in main() to which you assign the return from array_function, and properly allocated the array in array_function, then your code should be working without crashing. Also, M_PI should be properly typed as double eliminating the integer division concern.
You must VALIDATE ALL USER INPUT (sorry for all caps, but if you learn nothing else here, learn that). That means validating the return of scanf and checking the range of the value entered where appropriate.
Putting those pieces together, you could do something like the following (with the code sufficiently spaced so old-eyes can read it):
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <math.h>
#define MAXC 100 /* if you need a constant, define one */
double complex convert (double R, int p)
{
double complex Z = 0 + 0 * I; /* space your code so it is readable */
double complex A, B, C; /* (especially for older eyes......) */
A = exp (M_PI / 4.0) + 0 * I;
B = cos (11 * M_PI / 6.0 + 2 * p * M_PI) + 0 * I;
C = I * sin (R * M_PI / 6.0);
Z = A * ((R * B) + C);
return Z;
}
double complex *array_function (double *a, int n)
{
int i;
double complex *array = calloc (MAXC, sizeof *array); /* allocate */
if (!array) { /* validate allocation succeeded */
perror ("calloc-array");
exit (EXIT_FAILURE);
}
for (i = 0; i < n; i++) /* convert your values */
array[i] = convert (a[i], i);
return array; /* return pointer */
}
int main (void)
{
int N, i;
double complex *new_array; /* declare pointer to receive return */
double array[MAXC];
printf ("Enter array length: ");
if (scanf("%d", &N) != 1 || N > MAXC) { /* VALIDATE ALL USER INPUT */
fprintf (stderr, "error: invalid input or out of range.\n");
return 1;
}
for (i=0; i<N; i++) {
printf (" enter array[%2d]: ", i);
if (scanf("%lf", &array[i]) != 1) { /* VALIDATE ALL USER INPUT */
fprintf (stderr, "error: invalid conversion, array[%d].\n", i);
return 1;
}
}
new_array = array_function (array, N); /* call array_function */
printf("\nThe new array is: \n\n");
for (i=0; i<N; i++) /* output results */
printf (" %10.6f + i%f \n", creal(new_array[i]), cimag(new_array[i]));
free (new_array); /* don't forget to free memory you allocate */
return 0;
}
(note: you should free all memory you allocate)
Example Use/Output
$ ./bin/complex
Enter array length: 5
enter array[ 0]: 1.81
enter array[ 1]: 1.97
enter array[ 2]: .31
enter array[ 3]: 2.51
enter array[ 4]: 6.021
The new array is:
3.43798 + i1.781127
3.74189 + i1.881977
0.58883 + i0.354442
4.76758 + i2.121489
11.43651 + i-0.024116
Look things over and let me know if you have further questions.
double complex *new_array[100]; declares new_array to be an array of 100 pointers to double complex. That is not what you want. You merely want a pointer to double complex (which will point to the first element of an array that is provided by the function). The declaration for this is double complex *new_array;.
However, in array_function, you attempt to return array, where array is defined inside the function with double complex array[100];. That declaration, when used inside a function, declares an array that lasts only until the function returns. If you return its address (or the address of its first element), the pointer to that address will be invalid.
The proper way to return a new array from a function is to dynamically allocate the array, as with:
double complex *array = malloc(100 * sizeof *array);
if (!array)
{
fprintf(stderr, "Error, failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
… // Assign values to the array elements.
return array;
Then the caller is responsible for releasing the array at some later time, by passing the address to the free routine.
(To use malloc, free, and exit, add #include <stdlib.h> to your program.)
If you want to let the array_function create the content of new_array, you can send the array pointer as a parameter to the function, and let the function use that. You also need to change the definition of new_array to double complex new_array[100]
That is,
void array_function (double *a, double complex array[], int n)
{
int i;
for (i=0; i<n; i++)
{
array[i]=convert(*(a+i),i);
}
}
And in main():
double complex new_array[100];
...
array_function(array, new_array, N);

Error in my sorting program

#include <stdio.h>
#include <stdlib.h>
struct student{
char initials[2];
int score;
};
void sort(struct student* students, int n){
/*Sort the n students based on their initials*/
int i, j, replace;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
if(students[j] > students[j+1])
{
replace = students[j];
students[j] = students[j+1];
students[j+1] = replace;
}
}
}
}
int main(){
/*Declare an integer n and assign it a value.*/
int n=10;
/*Allocate memory for n students using malloc.*/
struct student* students = (struct student *)malloc(n*sizeof(struct student));
/*Generate random IDs and scores for the n students, using rand().*/
int i;
for(i=0; i<10; i++){
(students + i)->initials[1] = rand( ) % 26 + 'A';
(students + i)->initials[2] = rand( ) % 26 + 'A';
}
/*Print the contents of the array of n students.*/
for(i=0; i<10; i++){
printf("%c%c\n", students[i].initials[1], students[i].initials[2]);
}
/*Pass this array along with n to the sort() function*/
sort(students, n);
/*Print the contents of the array of n students.*/
return 0;
}
I get the following errors when i compile this code,
Program5.c: In function ‘sort’:
Program5.c:23:23: error: invalid operands to binary > (have ‘struct student’ and ‘struct student’)
if(students[j] > students[j+1])
^
Program5.c:25:17: error: invalid operands to binary == (have ‘int’ and ‘struct student’)
replace == students[j];
^
Program5.c:27:23: error: incompatible types when assigning to type ‘struct student’ from type ‘int’
students[j+1] = replace;
Any help would be highly appreciated :)
The first two errors mean that the compiler can't find a > (greater than) operator or a == (equal to) operator that compares a student to a student. The compiler can't just make one up. You need to write your own > and == operators.
The third error means the compiler can't find an assignment operator (=) that takes a student and assigns it to an int. Again, you need to write that operator, because the compiler doesn't know what you want to happen.
You should be able to find the proper syntax for defining these operators by searching for something along the lines of "define c++ == operator" or "define c++ assignment operator".
Remember that arrays in C/C++ are zero-based, and that you're over-writing memory in the initials generation code.
Also watch your array indices in the inner sorting loop; at some point j+1 will be equal to n, and you'll accessing storage that doesn't belong to you.
Your get your first error because the compiler doesn't know how to compare your student structs, it can't tell how to sort them. You must define the operator for this. For example, if you want to order them by score, you can change your student struct to:
struct student {
char initials[2];
int score;
friend bool operator > (const student& lhs, const student& rhs) {
return lhs.score > rhs.score;
}
};
The other two error are caused because you are trying to assign a student struct to an int (students[j] to replace), and vice-versa. Changing the type of replaceto student should fix this problem.
You need to define the following function:
/** #return 0 - if the students are the same
value greater than 0 - if the first student compares greater than the second
value less than 0 - if the second student compares greater than the first
*/
int cmp_student(const struct student* std1, const struct student* std2);
Then in your sort function you can use this function like so:
void sort(struct student* students, int n){
/*Sort the n students based on their initials*/
int i, j, replace;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
if(cmp_student(&students[j], &students[j+1]) < 0)
{
...
}
}
}
}
Note that there is a problem with the second nested loop in that function. What happens when j == (n - 1), what would the value of j + 1 be?
I would also recommend writing a swap function which takes two index positions and the array and swaps the contents of the array at those two positions. Something like this:
void swap(int id1, int id2, struct student* students);

Resources