I've been working through this problem, and I believe I have an error in where my pointers within my struct are pointing. However, I can't seem to figure out where I'm going wrong.
My code is meant to take in 2 complex numbers, then multiply and divide them, and then spit out both answers.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct complex_t
{
double real; // real part
double imag; // imaginary part
} complex_t;
// Multiplication Function //
void *multiply()
{
struct complex_t a, b, c;
c.real == ((a.real * b.real) - (a.imag * b.imag));
c.imag == ((a.imag * b.real) + (a.real * b.imag));
if ( c.imag >= 0 )
printf("Multiplication = %d + %di\n", c.real, c.imag); // Postive Imaginary case
else
printf("Multiplication = %d %di\n", c.real, c.imag); // Negative Imaginary case
}
// Division Function //
void *divide()
{
int numer1, numer2, denom;
struct complex_t a, b, c;
if ( b.real == 0 || b.imag == 0 ) // Case to Avoid Dividing by 0
printf("Division by 0 + 0i is not allowed.");
else
{
numer1 = ((a.real * b.real) + (a.imag * b.imag));
numer2 = ((a.imag * b.real) - (a.real * b.imag));
denom = ((b.real * b.real) + (b.imag * b.imag));
c.real == (numer1/denom);
c.imag == (numer2/denom);
if (numer2/denom >= 0)
printf("Division = %d + %di \n", c.real, c.imag); // Postive Imaginary case
else
printf("Division = %d %di \n", c.real, c.imag); // Negative imaginary case
}
}
// Main - to execute the two functions //
int main() {
struct complex_t a, b, c;
printf("Enter a and b where a + ib, for the first complex number.");
printf("\na = ");
scanf("%d", &a.real);
printf("b = ");
scanf("%d", &a.imag);
printf("Enter c and d where c + id, for the second complex number.");
printf("\nc = ");
scanf("%d", &b.real);
printf("d = ");
scanf("%d", &b.imag);
multiply();
divide();
return 0;
}
This is an example of what this program is producing:
Multiplication = 69144 -4196352i
Division = -13339222 0i
Any tips as to where I can start figuring this error out would be great.
C is an exact language. There is no such thing as syntax that is close enough. This is a great strength in C, but it is one hurdle beginning programmers have to come to terms with and understand before any real learning can take place. That includes understanding what each part of each line does, including the format strings. If you don't fully understand what each part of each line is doing -- look it up. Read the man pages, search for further information, until you do. It will save you a ton of time in the long run.
One of the things you can do that will, above all, help you find the problems in your code is to compile with Warnings enabled. That means including at least -Wall -Wextra in your compile string. For example, in your code, the screen was littered with warnings, including code with no apparent function and expected double but have int. Those things are telling you, you can try and run your code -- but DO NOT expect it to work right. You have to fix those, before you can have reasonable confidence that you will get more than garbage (or a crash) out of your code.
Another primary bit of learning that must take place is Always initialize your variables (to zero if nothing else). Attempting to access an uninitialized variable is Undefined Behavior. (it's anybody's guess what will happen.)
That being said. You had part of the code right. Your issues basically took slowing down, reading what the compiler was telling you was wrong, fixing it, and trying again. That's the key to C, slow down and get it right.
Enough blather -- are you going to help or not? Of course. Read through the following. Understand why the changes were necessary, and you will be able to consider it a good bit of learning for the day. However, the fixes in the code below, are not near as important as the guidance above for approaching C programming. (give a man a fish....):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
double real; // real part
double imag; // imaginary part
} complex_t;
// Multiplication Function //
void multiply (complex_t *a, complex_t *b, complex_t *c) {
/* struct complex_t a, b, c; */
c->real = ((a->real * b->real) - (a->imag * b->imag));
c->imag = ((a->imag * b->real) + (a->real * b->imag));
if (c->imag >= 0)
printf ("\nMultiplication = %f + %fi\n", c->real, c->imag); // Postive Imaginary case
else
printf ("\nMultiplication = %f %fi\n", c->real, c->imag); // Negative Imaginary case
}
// Division Function //
void divide (complex_t *a, complex_t *b, complex_t *c) {
int numer1, numer2, denom;
/* struct complex_t a, b, c; */
if (b->real == 0 || b->imag == 0) // Case to Avoid Dividing by 0
printf ("Division by 0 + 0i is not allowed.");
else {
numer1 = ((a->real * b->real) + (a->imag * b->imag));
numer2 = ((a->imag * b->real) - (a->real * b->imag));
denom = ((b->real * b->real) + (b->imag * b->imag));
c->real = (numer1 / denom);
c->imag = (numer2 / denom);
if (numer2 / denom >= 0)
printf ("\nDivision = %f + %fi \n", c->real, c->imag); // Postive Imaginary case
else
printf ("\nDivision = %f %fi \n", c->real, c->imag); // Negative imaginary case
}
}
// Main - to execute the two functions //
int main () {
complex_t a = { 0, 0 }, b = { 0, 0 }, c = { 0, 0 };
printf ("\nEnter a and b where a + ib, for the first complex number.\n\n");
printf (" a (a.real) = ");
scanf ("%lf", &a.real);
printf (" b (a.imag) = ");
scanf ("%lf", &a.imag);
printf ("\nEnter c and d where c + id, for the second complex number.\n\n");
printf (" c (b.real) = ");
scanf ("%lf", &b.real);
printf (" d (b.imag) = ");
scanf ("%lf", &b.imag);
multiply (&a, &b, &c);
divide (&a, &b, &c);
printf ("\n");
return 0;
}
output:
$ ./bin/divmult
Enter a and b where a + ib, for the first complex number.
a (a.real) = 10
b (a.imag) = 3
Enter c and d where c + id, for the second complex number.
c (b.real) = 5
d (b.imag) = 5
Multiplication = 35.000000 + 65.000000i
Division = 1.000000 + 0.000000i
void *multiply()
The values of struct variables a and b are not initialized within this function you should be passing the scanned values in main() to this function as well as divide()
There is no reason here I see why you are returning void *. Pass parameters by reference or by value.
Related
This is a very simple program, it just calculate the area of a triangle using Heron's formula, but I wanted to over complicate things a bit, so I made some functions that have pointers as parameters, which, in this case, they pretty much work like c++ references.
It works like that : it takes 3 sides (a,b,c) and calculates the area. The only problem is, whenever I enter a, I receive as an output -nan, which I did not understand why this happened.
When this sort of thing happens, is easy to blame the pointers, although is more likely the scanf or printf functions aren't behaving well.
If anyone could please explain to me why this is happening and how I can fix things up, I would be much thankful.
My code is bellow :
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
void CalculateSemiPerimeter(double a, double b, double c, double *result)
{
*result = ((a+b+c)/2.0);
}
void heron(double *semiPerimeter, double a, double b, double c, double *result) //note that semiPerimeter and result have the same adresses
{
double sub1 = (*semiPerimeter - a);
double sub2 = (*semiPerimeter - b);
double sub3 = (*semiPerimeter - c);
double mult = (*semiPerimeter*(sub1)*(sub2)*(sub3)); //this part may be wrong
*result = mult;
}
int main()
{
double a, b, c, result;
scanf("%lf, %lf, %lf", &a, &b, &c);
CalculateSemiPerimeter(a,b,c, &result);
heron(&result, a, b, c, &result);
result = sqrt(result);
printf("%.2lf", result);
}
and here's a example of an input :
>>5
which brings as output :
-nan
At least these issues:
Unchecked input
The return value of scanf() was unchecked. If a,b,c were successfully written, scanf() returns 3.
// scanf("%lf, %lf, %lf", &a, &b, &c);
if (scanf("%lf, %lf, %lf", &a, &b, &c) != 3) {
fprintf(stderr, "Input failure.\n");
return EXIT_FAILURE;
}
This would happen if input was "1 2 3" as the format expects "1,2,3" - commas between the numbers.
Further, code should sanitize inputs, checking if any are negative.
Advanced: Computational error
With extreme values, say when a much greater than b and b much greater than c, *semiPerimeter - a may result in severe loss of precession or even a negative number leading to a later trouble with sqrt(some_negative).
Instead code could be more careful and reduce computational errors. Rather than form sub1 with (a + b + c)/2 - a, use (-a + b + c)/2. This reduces cancellation error.
One level of improvement:
// Return the result and no need to pass in semiPerimeter.
// void heron(double *semiPerimeter, double a, double b, double c, double *result)
double heron(double a, double b, double c) {
double semiPerimeter = (a + b + c)/2;
double sub1 = (-a + b + c)/2;
double sub2 = ( a - b + c)/2;
double sub3 = ( a + b - c)/2;
return semiPerimeter * sub1 * sub2 * sub3;
}
Still with pathological inputs (unreal triangle lengths), the return value of heron() may be negative.
result = heron(a, b, c);
if (result < 0.0) {
; // TBD code that reports error.
} else {
result = sqrt(result);
...
}
2nd level of improvement:
Sort a, b, c by magnitude, greatest to least.
Change to below to further reduce cancelation error.
double sub3 = ( a + (b - c))/2;
I have the following code in c
#include <stdio.h>
int main(void)
{
int a, b, c, sum;
double d, p;
sum = a + b + c;
printf("请输入三个整数:");
scanf("%d %d %d", &a, &b, &c);
d = sum / 3;
printf("3个整数的平均值是:d=%.2f", d);
p = a / sum * 100;
printf(",第一个数占和的比例是:p=%4.2f%%", p);
}
It is about entering three integers from the keyboard, average them, and calculate the ratio of the first number to the sum of the three numbers. The output result retains 2 decimal places .
I cannot find where is wrong.
The two main issues are:
You calculate sum with uninitialized values for a, b and c. Move that calculation to after a successful scanf() to ensure those variables are set.
You probably want to do the calculations of d and p with double, rather than integer, precision. I make use of automatic type conversion via fractional constants. The other two options are to change the type of sum from an int to a double, or explicitly use a type cast (see answer by #FeihuLiu).
Minor issues:
Original code was formatted poorly (since fixed by one of our friends :-).
Optional for main() but it's a good idea to return an integer as your declaration said you would.
(not fixed) If you don't use p or d for anything else, consider just eliminating them in favor of doing the calculation call to printf()
It's generally a good idea to reduce the scope of variables so I moved those definitions to just before they are used.
#include <stdio.h>
int main(void) {
printf("请输入三个整数:");
int a, b, c;
if (scanf("%d %d %d", &a, &b, &c) != 3) {
// TBD: translate error message
printf("scanf failed\n");
return 1;
}
int sum = a + b + c;
double d = sum / 3.0;
printf("3个整数的平均值是:d=%.2f", );
double p = 100.0 * a / sum;
printf(",第一个数占和的比例是:p=%4.2f%%", p);
return 0;
}
Besides the sum problem, integer division will result in integer. You can use the following code:
#include <stdio.h>
int main(void) {
int a, b, c, sum;
double d, p;
printf("请输入三个整数:");
scanf("%d %d %d", &a, &b, &c);
sum = a + b + c;
d = (double) sum / 3;
printf("3个整数的平均值是:d=%.2f", d);
p = (double) a / sum * 100;
printf(",第一个数占和的比例是:p=%4.2f%%", p);
}
I created a vector struct and an addVector and subVector functions. I also created a print vector function.
I need to create 4 vector instances: two for input, two for output (one for the addition and one for the subtraction). I need to call printVector to print the result from addVector and the result from subVector. I think most of it is correct. I am just not sure what to do.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
double x;
double y;
double z;
} VECTOR;
VECTOR addVector(VECTOR *addOne, VECTOR *addTwo) {
double addX = addOne->x + addTwo->x;
double addY = addOne->y + addTwo->y;
double addZ = addOne->z + addTwo->z;
};
VECTOR subVector(VECTOR *subOne, VECTOR *subTwo){
double subX = subOne->x - subTwo->x;
double subY = subOne->y - subTwo->y;
double subZ = subOne->z - subTwo->z;
};
void printVector(VECTOR *printVector) {
printf("%lf, %lf, %lf\n", printVector->x, printVector->y, printVector->z);
};
void main() {
VECTOR A;
VECTOR B;
VECTOR C = addVector(&A, &B);
VECTOR D = subVector(&A, &B);
printf("Enter three doubles.\n");
scanf_s("%lf %lf %lf", &A.x, &A.y, &A.z);
addVector(&A, &B);
printVector(&C);
subVector(&A, &B);
printVector(&D);
system("pause");
};
You compute the values of the VECTOR coordinates in addVector and subVector, but you do not return a VECTOR structure.
Here is how to do it, and also note that since the VECTOR arguments are not modified, the pointers should be const qualified to underscore this property:
VECTOR addVector(const VECTOR *addOne, const VECTOR *addTwo) {
VECTOR add;
add.x = addOne->x + addTwo->x;
add.y = addOne->y + addTwo->y;
add.z = addOne->z + addTwo->z;
return add;
}
VECTOR subVector(const VECTOR *subOne, const VECTOR *subTwo) {
VECTOR sub;
sub.x = subOne->x - subTwo->x;
sub.y = subOne->y - subTwo->y;
sub.z = subOne->z - subTwo->z;
return sub;
}
void printVector(const VECTOR *printVector) {
printf("%lf, %lf, %lf\n", printVector->x, printVector->y, printVector->z);
}
In your main function, you use vectors A and B before initializing them or reading their values from the user. Modify the code this way:
void main() {
VECTOR A = { 0, 0, 0 };
VECTOR B = { 0, 0, 0 };
VECTOR C, D;
printf("Enter three doubles for A\n");
scanf_s("%lf %lf %lf", &A.x, &A.y, &A.z);
printf("Enter three doubles for B\n");
scanf_s("%lf %lf %lf", &B.x, &B.y, &B.z);
C = addVector(&A, &B);
printVector(&C);
D = subVector(&A, &B);
printVector(&D);
system("pause");
}
Finally, do not put a ; after the body of your functions.
Note also that you should enable all compiler warnings as it can help avoid silly bugs such as the above. Use gcc -Wall -W or clang -Weverything for command line compilers, and increase the warning level in the Visual Studio IDE if you use that.
addVector and subVector compute the components of the new vector, but don't actually return a new vector. But then, you call addVector and subVector and ignore the return value, so at least you are consistent.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct vector
{
double x;
double y;
double z;
};
struct vector *array;
double length(struct vector*);
int main()
{
int num,i;
double xin;
double yin;
double zin;
char buffer[30];
char buffer2[30];
printf("Enter number of vectors:");
fgets(buffer, 30, stdin);
sscanf(buffer, "%d", &num);
array = malloc( sizeof(struct vector) * num);
for(i=0;i<=num;i++)
{
printf("Please enter x y z for the vector:");
fgets(buffer2,100,stdin);
sscanf(buffer2, " %lf %lf %lf", &xin, &yin, &zin);
array[i].x = xin;
array[i].y = yin;
array[i].z = zin;
}
for(i=0;i<=num;i++)
{
printf( "Vector:%lf %lf %lf has a length of %lf\n", array[i].x, array[i].y, array[i].z, length(&array[i]));
}
}
double length(struct vector* vec)
{
return sqrt( (vec->x * vec->x) + (vec->y * vec->y) + (vec->z * vec->z) );
}
Ok the above code is almost finished it asks user for number of vectors then it asks user for the values of those vectors it then will calculate the length and print it out correspondingly.
I am trying to get some error checking in here but I cannot seem to get it...I looked up every possible return value for fgets and sscanf I just cant seem to get it
Defensive features
FIRST printf-------input should only be a single number greater than 0 and EOF should return a message like printf("enter a number--bye!") so I tried
while( sscanf(buffer, "%d", &num) ==1 && num > 0 )
but it still works if something like 3dadswerudsad is entered
also when the user is entering the 3 values for the vector if anything at all other than 3 doubles are entered for a vector the program should terminate with a message so I tried
while( sscanf(buffer2, "%lf %lf %lf", &xin, &yin, &zin) ==3 )
but it doesn't check for these incorrect inputs!!
I am going crazy
You are almost right, you need to name the formal and the function and to use it appropriately:
double veclength (struct vector v) {
return sqrt( (v.x * v.x) + (v.y * v.y) + (v.z * v.z) );
}
for efficiency and other reasons you might consider passing a pointer (to a constant vector, since you don't modify it)
double veclengthptr (const struct vector* v) {
return sqrt( (v->x * v->x) + (v->y * v->y) + (v->z * v->z) );
}
and then you could later use veclength(array[i]) or veclengthptr(array+i) (same as veclengthptr(&a[i]))
You should want to give prototypes (perhaps in some header file) before using these functions :
double veclength (struct vector);
double veclengthptr (const struct vector*);
Notice that for efficiency reasons you might want to declare these prototypes as static inline (and give their implementation in the same translation unit), so to ask for inline functions:
static inline double veclength (struct vector);
Take the habit of compiling with all warnings & debug info, e.g. gcc -Wall -Wextra -g
Regarding your use of sscanf(3) as sscanf(buf, "%d", &num) notice that if buf contains 3dxde it succeeds by reading 3 into num (with dxde unparsed). You might want to use %n in sscanf (read its documentation!) or use strtol(3)
The function could be implemented as follows.
double length(struct vector vec)
{
return sqrt( vec.x*vec.x + vec.y*vec.y + vec.z*vec.z );
}
I have written a small piece of code to calculate quadratic equations, but if the discriminant is negative, i wanted it to write that there are no real numerical values for this quadratic equation.
To make this happen, I had to call a function with a fourth parameter of 0, which i think , i have no idea why, would be a bad programming practice ? Is it the case or am i just being too picky of my code ? Thank you. (The reason I'm asking this is because i dont want to pick up some bad habits early on in my programming 'career').
Here's the code.
#include <stdio.h>
#include <math.h>
#include <string.h>
double quadratic_equation(double a, double b, double c, double d);
int main(void)
{
char command[20];
int i;
printf("Enter your command: ");
fgets(command, 20, stdin);
for (i = 0; i < 20; i++) {
if (command[i] == '\n') {
command[i] = '\0';
break;
}
}
if (strcmp(command, "quadratic equation") == 0) {
double a, b, c, x;
printf("Enter A: ");
scanf("%lf", &a);
printf("Enter B: ");
scanf("%lf", &b);
printf("Enter C: ");
scanf("%lf", &c);
x = quadratic_equation(a, b, c, 0); // THIS PIECE HERE MIGHT BE BAD PRACITCE ?
if (x == 0) {
printf("There are no real numerical values to this quadratic equation.");
}
else {
printf("------------\n");
printf("x1 = %.2f\n", quadratic_equation(a, b, c, 1));
printf("x2 = %.2f", quadratic_equation(a, b, c, -1));
}
}
return 0;
}
double quadratic_equation(double a, double b, double c, double d) {
double discriminant, x, insideroot;
insideroot = ((b*b) - (4*a*c));
if (insideroot < 0) {
return 0;
}
discriminant = sqrt(insideroot);
x = (-b + (d * discriminant)) / (2 * a);
return x;
}
Thank you very much for your help :d !
This certainly is bad practice. Since the roots of a formula a, b, and c an be any double you do need some sort of passing.
I would suggest a parameter that is a pointer to an int. If the pointer is NULL it is ignored, otherwise it will be set to 1 or 0 depending whether a real root exists:
double quadratic_equation(double a, double b, double c, int *root_exists) {
double discriminant;
discriminant = ((b*b) - (4*a*c));
if (discriminant < 0) {
if (root_exists != NULL) *root_exists = 0;
return 0.0;
}
x = (-b + sqrt(discriminant)) / (2 * a);
if (root_exists != NULL) *root_exists = 1;
return x;
}
A more rigorous approach is this:
typedef struct {
int num_roots;
double roots[2];
} quadratic_roots_t;
quadratic_roots_t quadratic_equation(double a, double b, double c) {
quadratic_roots_t roots;
double d;
d = b*b - 4*a*c;
if (d < 0.0) {
roots.num_roots = 0;
} else if (d == 0.0) {
roots.num_roots = 1;
roots.roots[0] = -b / (2 * a);
} else {
roots.num_roots = 2;
roots.roots[0] = (-b - sqrt(d)) / (2 * a);
roots.roots[1] = (-b + sqrt(d)) / (2 * a);
}
return roots;
}
I'd say it's not great to do. What you could do is something like this:
int quadratic_equation(double a, double b, double c, double *root_a, double *root_b) {
double discriminant = ((b*b) - (4*a*c));
if (discriminant < 0) {
return -1;
}
if (root_a != NULL) {
*root_a = (-b + sqrt(discriminant)) / (2 * a);
}
if (root_b != NULL) {
*root_b = (-b - sqrt(discriminant)) / (2 * a);
}
return 0;
}
Then you could call that like so:
double root_a;
double root_b;
int ok = quadratic_equation(a, b, c, &root_a, &root_b);
if (ok < 0) {
// It wasn't OK. Print out an error.
} else {
// It was OK. Print out the results.
}
Note that you should also check other error cases in the function and return -1 for them as well. E.g. a being zero.
Consider using the return value to indicate whether everything worked, and passing an array to the function to receive the return values:
enum QE_Status { QE_OK = 0, QE_NON_QUADRATIC, QE_COMPLEX_ROOTS, QE_NULL_POINTER };
enum QE_Status quadratic_equation(double a, double b, double c, double *r)
{
double discriminant;
if (r == 0)
return QE_NULL_POINTER;
if (a == 0.0)
return QE_NON_QUADRATIC;
discriminant = (b * b) - (4 * a * c);
if (discriminant < 0)
return QE_COMPLEX_ROOTS;
discriminant = sqrt(discriminant);
r[0] = (-b + discriminant) / (2 * a);
r[1] = (-b - discriminant) / (2 * a);
return QE_OK;
}
You can extend the system to handle numerical instability (because b*b is almost equal to 4*a*c, or because a is very small, etc).
The calling code can then be:
double a, b, c, x[2];
if (quadratic_equation(a, b, c, x))
...oops, something went wrong...
Or:
switch (quadratic_equation(a, b, c, x))
{
case QE_OK:
...print or use results in x...
break;
case QE_NON_QUADRATIC:
case QE_COMPLEX_ROOTS:
...print appropriate error message about user's data...
break;
case QE_NULL_POINTER:
...Oops - programming error...
break;
}
I would certainly call it bad practice because the code is very unclear.
Firstly, you are calling the function three times, when once should be enough.
I'd consider returning/filling a list in your quadratic_equation() function instead of returning the roots one by one.
This would also allow you to determine if there are real roots -- if there aren't, just return an empty list.
As a whole, this would be much more elegant than your current solution, and it would eliminate the need for checking whether there are any solutions beforehand.