I'm working on a project for a class and have been stuck for quite a while. When I unit tested the input earlier, it accepted the values for numOfDataSets and createDataSets without error. Now, however, after typing in any set of values for createDataSets, the code freezes after the first input until I enter any character (such as 1 or a), then errors with a segmentation fault. I am not sure what went wrong, and I would appreciate any help.
#include <stdio.h>
#include <stdlib.h>
// Function to return the number of data sets the user wants.
int numOfDataSets(void) {
int ret;
printf("Enter number of data sets: ");
scanf("%d", &ret);
return ret;
}
// Function that creates the data sets in the input arrays.
void createDataSets(float **inputArr, int inputLength, int *lengths) {
int i = 0, j, k;
float value, *currentSet;
// For every element in inputArr...
while (i < inputLength) {
printf("Enter the number of values in this data set, followed by the values: ");
scanf("%d", &j);
*(lengths + i) = j;
currentSet = (float*)calloc(j, sizeof(float));
k = 0;
while (k < j-1) {
scanf("%f", &value);
*(currentSet + k) = value;
k++;
}
scanf("%f", &value);
*(currentSet + j - 1) = value;
*(inputArr + i) = (float*)¤tSet;
i++;
}
}
// Function to get int value of data set to choose.
int chooseDataSet(void) {
int ret;
printf("Enter the number of the data set on which you wish to do calculations: ");
scanf("%d", &ret);
ret = ret - 1;
return ret;
}
// Gets the number option of the operation that the user wants to do.
int getOption(void) {
int ret;
printf("Enter one of the following numbers:\n");
printf("1. Find the minimum value.\n");
printf("2. Find the maximum value.\n");
printf("3. Calculate the sum of all the values.\n");
printf("4. Calculate the average of all the values.\n");
printf("5. Sort the values in ascending order (i.e., from smallest to largest).\n");
printf("6. Select a different data set.\n");
printf("7. Exit the program.\n");
scanf("%d", &ret);
return ret;
}
// Function to find the minimum value of a dataset.
void minimum(float *ptr, int length) {
int i = 1;
float min;
min = *(ptr);
while (i < length) {
if (*(ptr + i) < min) {
min = *(ptr + i);
}
i++;
}
printf("The minimum value of the set is: %d\n", min);
}
// Function to find the maximum value of a dataset.
void maximum(float *ptr, int length) {
int i = 1;
float max;
max = *(ptr);
while (i < length) {
if (*(ptr + i) > max) {
max = *(ptr + i);
}
i++;
}
printf("The maximum value of the set is: %d\n", max);
}
// Function to find the sum of the values of a dataset.
void sum(float *ptr, int length) {
int i = 1;
float sum;
sum = *(ptr);
while (i < length) {
sum = sum + *(ptr + i);
i++;
}
printf("The sum of the set is: %d\n", sum);
}
// Function to find the average of the values of a dataset.
void average(float *ptr, int length) {
int i = 1;
float sum;
sum = *(ptr);
while (i < length) {
sum = sum + *(ptr + i);
i++;
}
sum = sum / length;
printf("The average of the set is: %d\n", sum);
}
// Function to sort the values of a dataset.
void sort(float *ptr, int length) {
int i = 1, j;
float temp;
while (i < length) {
j = i;
while ((j > 0) && (*(ptr + j - 1) > *(ptr + j))) {
temp = *(ptr + j);
*(ptr + j) = *(ptr + j - 1);
*(ptr + j - 1) = temp;
j--;
}
i++;
}
printf("The sorted array is: ");
i = 0;
while (i < length) {
printf("%f\t", *(ptr + i));
i++;
}
printf("\n");
}
// Main method...
int main(void) {
int *lengths, outerLength, userChoiceSet = 0, userChoiceOption = 0, breakOutterLoop = 0;
float **outer;
outerLength = numOfDataSets();
outer = (float**)calloc(outerLength, sizeof(float*));
lengths = (int*)calloc(outerLength, sizeof(int));
createDataSets(outer, outerLength, lengths);
while (breakOutterLoop == 0) {
userChoiceSet = chooseDataSet();
while ((userChoiceOption != 6) || (userChoiceOption != 7)) {
userChoiceOption = getOption();
switch (userChoiceOption)
{
case 1:
minimum(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 2:
maximum(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 3:
sum(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 4:
average(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 5:
sort(*(outer + userChoiceSet), *(lengths + userChoiceSet));
break;
case 7:
breakOutterLoop = 1;
default:
break;
}
}
}
return (0);
}
The type of input to expect from the user would be something like:
2
3 1.2 2.3 3.4
4 4.5 5.6 6.7 7.8
Your main problem is this, in createDataSets():
*(inputArr + i) = (float*)¤tSet;
What this actually does is assign the address of currentSet to each element of inputArr. This address doesn't change on each iteration, so each element of inputArr gets set to the exact same value. Moreover, this address refers to a variable local to createDataSets() which will be destroyed when that function returns, so the address will be invalid. All the arrays you're dynamically creating are just being discarded, because you're not storing the addresses.
What you should have is:
inputArr[i] = currentSet;
As you mention in the comments, your compiler warned you about this, because what you were doing was trying to store a float ** in a float *, which is rarely a good idea. By adding the cast you silenced the warning, but you didn't fix the problem it was warning you about. The number of occasions in C where a cast is actually what you want to do are relatively few. None of the casts in your program are either necessary, or wise.
A few other points...
You use the wrong format specifier in many of your printf() calls. The %d here:
printf("The minimum value of the set is: %d\n", min);
for instance, should be an %f, because min is a float.
You are overusing pointer notation which makes your code very difficult to follow. That includes very difficult for you, too. For instance, your minimum() function could be much better written as so:
void minimum(float *ptr, int length) {
float min = ptr[0];
for ( int i = 0; i < length; ++i ) {
if ( ptr[i] < min ) {
min = ptr[i];
}
}
printf("The minimum value of the set is: %f\n", min);
}
Similarly, in your switch statement, something like:
average(*(outer + userChoiceSet), *(lengths + userChoiceSet));
is much more clearly written as:
average(outer[userChoiceSet], lengths[userChoiceSet]);
You are missing a call to fflush(stdout) in a few places, where you prompt for input but do not end the prompt with an '\n'. When I ran this code on my system, the prompt did not show before it sat to wait for the input. Interactive output is line-buffered by default, in C, and if you want things to be predictable, then you need to output a '\n' or call fflush(stdout) when output needs to be displayed.
You would benefit from defining your variables closer to the time of use. Restricting the scope of your variables to the minimum feasible is generally good. For instance, in your main() function, your variable userChoiceSet is never used outside of the outer while loop, so define it inside with:
while (breakOutterLoop == 0) {
int userChoiceSet = chooseDataSet();
You don't check the return from calloc() anywhere - you must do this, because the allocation might fail. malloc() and friends return NULL on failure. There's also no real point using calloc(), here - malloc() would be more normal.
You seem to use while loops in places where for loops would be much more natural.
You haven't done too bad a job with this one, but you'll find writing larger programs easier if you make each function do just one thing. For instance, your minimum() function should just calculate the minimum, but right now it calculates it and prints it. Particularly when it comes to dealing with input in the wrong format (see point 9 below) wrapping this up in a separate function will make the functions that use that input much less cluttered, and it's easy to get a function correct and to visually debug it if it's not doing a bunch of different things at once. Also, your opportunity for reusing code goes up when you do this (e.g. right now you couldn't use that minimum() function at any place where you wanted to calculate the minimum without also printing it).
Overall, having one array for your values, and a second for their lengths, is not a good approach. Far better would be to have an array of structs, each struct having a member for the array, and a member for the length, so the two related pieces of data are packaged together.
Also, your use of scanf() is potentially troublesome. If you enter input that's not expected, your program will not fail gracefully. For instance, if you enter anything other than a number in your main menu, then you'll go into an infinite loop. Generally better is to use fgets() to read in an entire line, and use sscanf() to parse its contents. At a minimum, you should check the return from scanf() to see if it successfully read a value, and if it did not, take appropriate remedial action (like reading all the characters in the input buffer and going back to ask for more input).
Overall, bearing all of the above in mind except for the last two points, your createDataSets() function would be better looking something like this:
void createDataSets(float **inputArr, const int inputLength, int *lengths) {
for ( int i = 0; i < inputLength; ++i ) {
printf("Enter the number of values in this data set, "
"followed by the values: ");
fflush(stdout);
scanf("%d", &lengths[i]);
float * currentSet = malloc(lengths[i] * sizeof *currentSet);
if ( !currentSet ) {
perror("Couldn't allocate memory in createDataSets()");
exit(EXIT_FAILURE);
}
for ( int j = 0; j < lengths[i]; ++j ) {
scanf("%f", ¤tSet[j]);
}
inputArr[i] = currentSet;
}
}
Much easier to debug, easier to follow, and easier to not get wrong in the first place.
Since I've got a bit of time on my hands, here's how I'd figure it:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
/* Maximum length of input buffer */
#define MAX_LINE 1024
/* Dataset structure */
struct dataset {
float * data;
size_t length;
};
/* Gets a single integer from user */
int getInteger(const char * prompt)
{
int value;
bool first_try = true;
char buffer[MAX_LINE];
do {
printf("%s%s: ", first_try ? "" : "Try again - ", prompt);
fflush(stdout);
fgets(buffer, MAX_LINE, stdin);
first_try = false;
} while ( sscanf(buffer, "%d", &value) != 1 );
return value;
}
/* Gets a bounded integer from user */
int getBoundedInteger(const char * prompt, const int min, const int max)
{
bool bad_input;
int value;
do {
bad_input = false;
value = getInteger(prompt);
if ( value < min ) {
printf("Too low, try again - ");
bad_input = true;
}
else if ( value > max ) {
printf("Too high, try again - ");
bad_input = true;
}
} while ( bad_input );
return value;
}
/* Gets a list of floats from user - caller must free */
float * getFloats(const char * prompt, const int num)
{
float * values = malloc(num * sizeof *values);
if ( !values ) {
perror("Couldn't allocate memory in getFloats()");
exit(EXIT_FAILURE);
}
bool bad_input = false;
do {
printf("%s%s: ", bad_input ? "Try again - " : "", prompt);
fflush(stdout);
char buffer[MAX_LINE];
fgets(buffer, MAX_LINE, stdin);
char * ptr = buffer;
int num_read = 0;
bad_input = false;
while ( *ptr && num_read < num ) {
/* Skip leading whitespace */
while ( *ptr && isspace(*ptr) ) {
++ptr;
}
/* Get and check input */
char * endptr;
float val = strtof(ptr, &endptr);
if ( ptr == endptr ) {
bad_input = true;
break;
}
/* Advance ptr and store input if good */
ptr = endptr;
values[num_read++] = val;
}
if ( num_read < num ) {
bad_input = true;
}
} while ( bad_input );
return values;
}
/* Returns the number of data sets the user wants. */
int numOfDataSets(void)
{
return getInteger("Enter number of data sets");
}
/* Creates the data sets */
void createDataSets(struct dataset ** sets, const int set_length)
{
for ( int i = 0; i < set_length; ++i ) {
struct dataset * new_set = malloc(sizeof *new_set);
if ( !new_set ) {
perror("Couldn't allocate memory for dataset");
exit(EXIT_FAILURE);
}
new_set->length = getInteger("Enter number of values in set");
new_set->data = getFloats("Enter values", new_set->length);
sets[i] = new_set;
}
}
/* Gets the number of data set to choose */
int chooseDataSet(const int min, const int max)
{
return getBoundedInteger("Choose data set", min, max) - 1;
}
/* Gets a menu choice from the user */
int getOption(void)
{
printf("Enter one of the following numbers:\n");
printf("1. Find the minimum value\n");
printf("2. Find the maximum value\n");
printf("3. Calculate the sum of all the values\n");
printf("4. Calculate the average of all the values\n");
printf("5. Sort the values in ascending order\n");
printf("6. Output the data set\n");
printf("7. Select a different data set\n");
printf("8. Exit the program\n");
return getInteger("Choose option");
}
/* Returns the minimum value in a data set */
float minimum(const struct dataset * set)
{
float min = set->data[0];
for ( size_t i = 0; i < set->length; ++i ) {
if ( set->data[i] < min ) {
min = set->data[i];
}
}
return min;
}
/* Returns the maximum value in a data set */
float maximum(const struct dataset * set)
{
float max = set->data[0];
for ( size_t i = 0; i < set->length; ++i ) {
if ( set->data[i] > max ) {
max = set->data[i];
}
}
return max;
}
/* Returns the sum of the data in a dataset */
float sum(const struct dataset * set)
{
float sum = 0;
for ( size_t i = 0; i < set->length; ++i) {
sum += set->data[i];
}
return sum;
}
/* Returns the arithmetic average of the data in a dataset */
float average(const struct dataset * set)
{
float sum = 0;
for ( size_t i = 0; i < set->length; ++i ) {
sum += set->data[i];
}
return set->length > 0 ? sum / set->length : sum;
}
/* Sorts the elements of a dataset in place */
void sort(struct dataset * set)
{
for ( size_t i = 0; i < set->length; ++i ) {
for ( size_t j = i; j && set->data[j-1] > set->data[j]; --j ) {
float temp = set->data[j];
set->data[j] = set->data[j-1];
set->data[j-1] = temp;
}
}
}
/* Prints a dataset */
void print_set(const struct dataset * set) {
for ( size_t i = 0; i < set->length; ++i ) {
printf("%.4f ", set->data[i]);
}
putchar('\n');
}
/* Main function */
int main(void)
{
/* Get and initialize sets */
const int num_sets = numOfDataSets();
struct dataset ** sets = malloc(num_sets * sizeof *sets);
if ( !sets ) {
perror("Couldn't allocate memory for sets");
return EXIT_FAILURE;
}
createDataSets(sets, num_sets);
/* Main menu */
int chosen_set = chooseDataSet(1, num_sets);
bool keep_going = true;
while ( keep_going ) {
switch ( getOption() )
{
case 1:
printf("Minimum value is %f\n\n",
minimum(sets[chosen_set]));
break;
case 2:
printf("Maximum value is %f\n\n",
maximum(sets[chosen_set]));
break;
case 3:
printf("Sum of values is %f\n\n",
sum(sets[chosen_set]));
break;
case 4:
printf("Average of values is %f\n\n",
average(sets[chosen_set]));
break;
case 5:
sort(sets[chosen_set]);
break;
case 6:
print_set(sets[chosen_set]);
break;
case 7:
chosen_set = chooseDataSet(1, num_sets);
break;
case 8:
keep_going = false;
break;
default:
break;
}
}
/* Free memory for sets */
for ( int i = 0; i < num_sets; ++i ) {
free(sets[i]->data);
free(sets[i]);
}
free(sets);
return 0;
}
Related
The following program attempts to read an input file line by line using fgets, and save each comma delimited float value into an array of structs using sscanf (this aspect of the code works fine). The issue lies in that the program should also detect when a float value is missing/empty, and assign it the float value 1.500 which then is saved into the array of structs.
EDIT: This is supposed to be compiled using VS2017, so on Windows.
*Note: Please note that the following questions have been studied before posting this question:
How to check if a string returned by scanf is null
How to get scanf to continue with empty scanset
An example of the input file (missing value in the second row):
0.123f, 0.234f, 0.345f, 0.456f, 0.567f
1.987f, , 7.376f, 2.356f, 5.122f
9.111f, 1.234f, 7.091f, 6.672f, 9.887f
Desired output (missing value in second row is detected and set to 1.500):
0.123 0.234 0.345 0.456 0.567
1.987 1.500 7.376 2.356 5.122
9.111 1.234 7.091 6.672 9.887
So far, the first attempt tried to scan all 5 floats (each with 'f' suffix) into strings and then check to see if those strings are null/empty or of zero length using strcmp and strlen, respectively, and finally involved trying to use sscanf again on each of those variables to read each into an array of structs.
The 2nd attempt included a check to see if the sscanf was successful by using if (sscanf(line, "%ff", &data[i].x) == NULL) { // ...some alert and assign 1.500}, which did not work either. The 3rd attempt, as seen below:
#include "stdio.h"
int main() {
typedef struct {
float x, y, vx, vy, mass;
}DATA;
FILE *file = fopen("null_detector.txt", "r");
if (file == NULL)
{
printf(stderr, "ERROR: file not opened.\n");
return EXIT_FAILURE;
}
int N= 3;
DATA* data = malloc(Nbodies * sizeof * data); // Array allocation
char line[256];
int i;
int inc = 1;
for (i = 0; i < Nbodies; i += inc)
{
fgets(line, sizeof(line), file);
// **Some info:
// Scan 5 float variables per line (this part works fine)
sscanf(line, "%ff, %ff, %ff, %ff, %ff",
&data[i].x, &data[i].y, &data[i].vx, &data[i].vy, &data[i].mass); // %ff accounts for 'f' suffix
// Now check if any of above vars are empty/NULL.
// NOTE: aware that these vars CANNOT be compared to NULL,
// but has been included to try and provide clarity for end goal
if (data[i].x == NULL)
{
//.. assign 1.500 to data[i].x
}
if (data[i].y == NULL)
{
//... same as above etc
}
// ...Repeat IF statements for all 5 vars
}
//Print the contents of array of structs to check for correct output
for (i = 0; i < Nbodies; i++)
{
printf("%.3f %.3f %.3f %.3f %.3f\n", data[i].x, data[i].y, data[i].vx, data[i].vy, data[i].mass);
}
return 0;
}
Summary:
Does anyone know how this program can be modified to:
detect missing float values in each line of the file upon reading them with fgets
replace missing float values with the float value 1.500
write these values to the array of structs, like the non-missing values successfully are doing?
As commented in the code, I am aware that the struct float variables cannot be compared to NULL. I have included this comparison in the code to only try to add some clarity as to what the end goal is.
You can use strsep to separate each line.
str = strsep(&line, ",")
Using one function to set the value of data:
void set_data(DATA *dt, int count, float f) {
switch(count) {
case 0: dt->x = f; break;
case 1: dt->y = f; break;
case 2: dt->vx = f; break;
case 3: dt->vy = f; break;
case 4: dt->mass = f; break;
}
}
The complete code:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
float x, y, vx, vy, mass;
}DATA;
void set_data(DATA *dt, int count, float f) {
switch(count) {
case 0: dt->x = f; break;
case 1: dt->y = f; break;
case 2: dt->vx = f; break;
case 3: dt->vy = f; break;
case 4: dt->mass = f; break;
}
}
int main() {
FILE *file = fopen("text.txt", "r");
if (file == NULL)
{
printf( "ERROR: file not opened.\n");
return EXIT_FAILURE;
}
int N= 3;
DATA* data = malloc(N * sizeof(data)); // Array allocation
char *line;
int i;
int inc = 1;
size_t n = 0;
for (i = 0; i < N; i += inc)
{
getline(&line, &n, file);
int count = 0;
char *str;
while((str = strsep(&line, ",")) != NULL) {
if (strcmp(str, " ") == 0) {
set_data(&data[i], count, 1.5);
} else {
set_data(&data[i], count, atof(str));
}
// printf("count = %d\n", count);
// printf("token: %s\n", str);
count++;
}
}
//Print the contents of array of structs to check for correct output
for (i = 0; i < N; i++)
{
printf("%.3f %.3f %.3f %.3f %.3f\n", data[i].x, data[i].y, data[i].vx, data[i].vy, data[i].mass);
}
return 0;
}
The input:
#cat text.txt
0.123f, 0.234f, 0.345f, 0.456f, 0.567f
1.987f, , 7.376f, 2.356f, 5.122f
9.111f, 1.234f, 7.091f, 6.672f, 9.887
The output:
0.123 0.234 0.345 0.456 0.567
1.987 1.500 7.376 2.356 5.122
9.111 1.234 7.091 6.672 9.887
It can also achieved with only sscanf if there is at least a space between the commas when there is an absence of an input value.
#include <stdio.h>
int main(void) {
char *str[] = {"0.123f, 0.234f, 0.345f, 0.456f, 0.567f",
"1.987f, , 7.376f, 2.356f, 5.122f",
"9.111f, 1.234f, 7.091f, 6.672f, 9.887f"};
float float_arr[3][5];
char temp[5][7];
for (unsigned i = 0; i < 3; i++) {
if (5 != sscanf(str[i], "%6[^,],%6[^,],%6[^,],%6[^,],%6[^,]",
temp[0], temp[1], temp[2], temp[3], temp[4]))
return printf("Error\n"), 1;
for (unsigned j = 0; j < 5; j++)
if (1 != sscanf(temp[j], "%ff", &float_arr[i][j]))
float_arr[i][j] = 1.500f;
}
// printing the result
for (unsigned i = 0; i < 3; i++) {
for (unsigned j = 0; j < 5; j++)
printf("%ff ", float_arr[i][j]);
printf("\n");
}
return 0;
}
Output
0.123000f 0.234000f 0.345000f 0.456000f 0.567000f
1.987000f 1.500000f 7.376000f 2.356000f 5.122000f
9.111000f 1.234000f 7.091000f 6.672000f 9.887000f
Nowadays, I'm working on a system kernel practice course. However, when I compare a system call with an user call, it's strange that the system call return a time count of 0 us (sometimes return 1). But I pass count=1e8 which is a quite big number.
I'm doubt that the computations didn't happen because the result is not used. Then I change add as result = result + 1 and print the final result. However, the result is right and the time count just from 0 or 1 change to 2-6.
long yanpan_oper(int* result,int num1,int num2,char* op)
{
if(op)
{
if(*op == '+')
{
*result = num1 + num2;
}
else if(*op == '-')
{
*result = num1 - num2;
}
else if(*op == '*')
{
*result = num1*num2;
}
else if(*op == '\\')
{
if(num2!=0)
*result = num1/num2;
else
printk("divided number can't be zero!\n");
}else
printk("unrecongized operator %c\n", *op);
}else
{
printk("operation is empty.\n");
}
return 0;
}
SYSCALL_DEFINE1(yanpan_func, int, count)
{
printk("The count is %d.\n", count);
struct timeval tstart, tend;
do_gettimeofday(&tstart);
int i;
for(i=0;i<count;i++) // +
{
int result;
char op_add = '+';
yanpan_oper(&result, i, 10, &op_add);
}
for(i=0;i<count;i++) // -
{
int result;
char op_sub = '-';
yanpan_oper(&result, i, 10, &op_sub);
}
for(i=0;i<count;i++) // *
{
int result;
char op_mul = '*';
yanpan_oper(&result, i, 2, &op_mul);
}
for(i=0;i<count;i++) // '//'
{
int result;
char op_div = '\\';
yanpan_oper(&result, i, 10, &op_div);
}
do_gettimeofday(&tend);
long delta_time = 1000000*(tend.tv_sec - tstart.tv_sec) + (tend.tv_usec - tstart.tv_usec);
printk("The start time is %ld.\n", tstart.tv_sec*1000000+tstart.tv_usec);
printk("The end time is %ld.\n", tend.tv_sec*1000000+tend.tv_usec);
printk("Syscall time use:%ld usec", delta_time);
return delta_time;
}
I have tried many times, but the result didn't change. The user call computation of the same amount takes around 1300 ms, can computations occur in kernel be fast like this?
Let's look at one loop:
for(i=0;i<count;i++) // +
{
int result;
char op_add = '+';
yanpan_oper(&result, i, 10, &op_add);
}
This will call the function yanpan_oper count times. But each time it will overwrite the previous result stored in result without using that value for the computation. Chances are that the compiler just optimized the whole loop away, replacing it with just one single call to yanpan_oper since the for loop is actually equivalent to just executing the loop body once.
Furthermore, the loop body ONLY affects variables inside the loop body, so not only can the compiler decide to just keep the last iteration. It can skip basically the whole code, so that what you're actually executing is this:
SYSCALL_DEFINE1(yanpan_func, int, count)
{
printk("The count is %d.\n", count);
struct timeval tstart, tend;
do_gettimeofday(&tstart);
do_gettimeofday(&tend);
long delta_time = 1000000*(tend.tv_sec - tstart.tv_sec) + (tend.tv_usec - tstart.tv_usec);
printk("The start time is %ld.\n", tstart.tv_sec*1000000+tstart.tv_usec);
printk("The end time is %ld.\n", tend.tv_sec*1000000+tend.tv_usec);
printk("Syscall time use:%ld usec", delta_time);
return delta_time;
}
Here are some tips for how to fool the optimizer:
// Create input that cannot be calculated at compile time
int input1[count];
int input2[count];
srand(time(NULL));
for(int i=0; i<count; i++) {
input1[i] = rand()%1000;
input2[i] = rand()%1000;
}
// Store the output, so that the optimizer cannot take away the loop
int output[count];
// Start timer
for(i=0;i<count;i++) // +
{
char op_add = '+';
yanpan_oper(&output[i], input1[i], input2[i], &op_add);
}
// End timer
// Use the output to that the optimizer cannot remove the array, and thus
// also the loop
for(int i=0; i<count; i++)
printf("%d ", output[i]);
Do note that those arrays may be to big for the stack. If that's the case, use this instead:
int *input1 = malloc(count * sizeof(*input1));
int *input2 = malloc(count * sizeof(*input2));
srand(time(NULL));
for(int i=0; i<count; i++) {
input1[i] = rand()%1000;
input2[i] = rand()%1000;
}
int *output = malloc(count * sizeof(*output));
(Remember to check if malloc succeeded and to free the memory afterwards)
I got this assignment as homework and I can't figure out how to do it:
Input is a string of the numbers 1, 2 and 3.
You need to build a function that determines if the number represented by the string is divisible by 3.
Rules:
No loops.
No math operations (+,-,*,/,%) on the number.
Use recursion.
Hint: if the sum of the digits of a number is divisible by 3 - so is the number.
I tried using the hint to come up with an algorithm to do this, but it does not work (if 1 and 2 appear an equal number of times, then the number is divisible by 3. But then if the number is composed of only 1 or 2 it can still be divisible, and we found ourselves again with the same problem).
Any ideas?
Well, how silly can you go? The entry point is divBy3_0, just call it with the string.
bool divBy3_0(char const *n);
bool divBy3_1(char const *n);
bool divBy3_2(char const *n);
bool divBy3_0(char const *n) {
switch(*n) {
case '1': return divBy3_1(&n[1]);
case '2': return divBy3_2(&n[1]);
case '3': return divBy3_0(&n[1]);
}
return true;
}
bool divBy3_1(char const *n) {
switch(*n) {
case '1': return divBy3_2(&n[1]);
case '2': return divBy3_0(&n[1]);
case '3': return divBy3_1(&n[1]);
}
return false;
}
bool divBy3_2(char const *n) {
switch(*n) {
case '1': return divBy3_0(&n[1]);
case '2': return divBy3_1(&n[1]);
case '3': return divBy3_2(&n[1]);
}
return false;
}
See it live on Coliru
Based on recursion and binary addition (without +-/*%)
recursively sum digits in input (sum_str_digits)
check is it dividable by 3 (is_dividable_by_3):
if number equals to 3 or 6 or 9 return 1 (true)
if number equals to 2,4,5,7,8 or 0 return 0 (false)
otherwise go to 1) with sum
Sample code, of course it needs care (error handling especially)
#include <stdio.h>
#include <stdlib.h>
int badd(int n1, int n2){
int carry, sum;
carry = (n1 & n2) << 1;
sum = n1 ^ n2;
if (sum & carry)
return badd(sum, carry);
else
return sum ^ carry;
}
char * int_to_str(int n) {
//int length_0 = snprintf( NULL, 0, "%d", n) + 1;
int length_0 = 32;
char* str = malloc(length_0);
snprintf( str, length_0, "%d", n);
return str;
}
int digit_to_int(char d) {
char str[2];
str[0] = d;
str[1] = '\0';
return (int) strtol(str, NULL, 10);
}
int sum_str_digits(char * s, int sum){
sum = badd(sum, digit_to_int(s[0]));
if (s[1] == '\0') {
printf("Sum: %d \n", sum);
return sum;
}
return sum_str_digits(&(s[1]), sum);;
}
int is_dividable_by_3(int n) {
switch (n) {
case 3:
case 6:
case 9:
return 1;
case 1:
case 2:
case 4:
case 5:
case 7:
case 8:
case 0:
return 0;
default: {
char * str = int_to_str(n);
int x = sum_str_digits(str, 0);
free(str);
return is_dividable_by_3(x);
}
}
}
int main(int argc, char *argv[]){
int sum;
sum = sum_str_digits(argv[1], 0);
printf("Is div by 3: %d \n", is_dividable_by_3(sum));
return 0;
}
Post edited - previous version
Recursive subtracting 3 in binary mode (without use of any math operator that are forbidden) until it equals three or less:
int badd(int n1, int n2){
int carry, sum;
carry = (n1 & n2) << 1; // Find bits that are used for carry
sum = n1 ^ n2; // Add each bit, discard carry.
if (sum & carry) // If bits match, add current sum and carry.
return badd(sum, carry);
else
return sum ^ carry; // Return the sum.
}
int bsub(int n1, int n2){
// Add two's complement and return.
return badd(n1, badd(~n2, 1));
}
int idiv3(int n) {
if (n == 3) {
return 1;
}
if (n < 3) {
return 0;
}
if (n > 3) {
return idiv3(bsub(n, 3));
}
}
int div3(const char *n) {
return idiv3(strtol(n, (char **) NULL, 10));
}
This one should work. It replaces continuously subtracting 3 from the number by starting a loop from 3 up to the number, keeping a loop counter and recursively calling itself. count++ does use some "+" character, but not the "+" operator and not on the number:
int f(int num){
int count = 0, i;
if(num == 3){
puts ("number is divisible by 3");
}
else if(num < 3){
puts ("number is not divisible");
}
else{
for (i = 3; i < num; i++){
count++;
}
num = count;
f (num);
}
}
void g (char *s) {
f (atoi (s));
}
A typical "write a program without writing a program" assignment. I'm a bit afraid you really cannot learn much with regards to practical programming from this. (Other than how to waste computing resources with silly programs that are only allowed to use a subset of the language.)
I suppose a modulo opperation on the sum is allowed, as long as the sum built using recursion. It could look as follows:
#include <stdio.h>
#include <stdlib.h>
int isDividableBy3_recursive(const char* n, int sum) {
if (!n || !*n) {
return (sum % 3 == 0) ? 1 : 0;
}
else {
return isDividableBy3_recursive(n+1, sum+(*n - '0'));
}
}
int isDividableBy3(const char* n) {
return isDividableBy3_recursive(n,0);
}
int main(int argc, char *argv[]){
char* testNumbers[] = { "100", "233", "345", "3", "", NULL };
for (int i=0;testNumbers[i]!=NULL;i++) {
char* testNumber = testNumbers[i];
printf("%s dividable by 3:%d\n", testNumber, isDividableBy3(testNumber));
}
return 0;
}
The problem here is that pretty much everything done by a computer is a mathematical operation. So I submit one that the compiler ought to optimise to a jump table. Here's the "Olafesque-compliant" solution.
switch (the_damn_number)
{
case 0:
return true;
case 1: case 2:
return false;
case 3:
return true;
// and so on
case largest_number_I_care_about:
// ToDo
}
(Use an if block if you're not allowed to convert the string to a switchable type.)
Use your favourite scripting tool to generate the code for you.
Here's how you do it.
Your first job is to use unsigned long long int strtoull(const char *nptr, char **endptr, int base); to convert the string to an unsigned long long. Then apply that to
bool is_divisible_by_3(unsigned long long n)
{
if (n > 9){
// more than one digit
return is_divisible_by_3(sum_digits_in_number(n));
} else {
return n == 0 || n == 3 || n == 6 || n == 9;
}
}
You need to build sum_digits_in_number(unsigned long long): it's difficult to see how you could do that without using +, /, or %, here's one way otherwise:
sum = 0;
while (n) {
sum += n % 10;
n /= 10;
}
I'm trying to create a calculator in c, which can calculate with priority and get right results for examples like these:
((5+5)/3)*3) -- > 9
((1+2) * 3) -- > 9
These examples my code below can calculate. But for something like this
(2+5) * (2+5), my program gives wrong answer.
I'm using 2 stacks. One for operators and one for numbers. It works on this principle:
follows:
((4 - 2) * 5) + 3 --> normal infix expression:
+ * - 4 2 5 3
Pseudo code:
Read + (an operation), push it onto the stack,
Read * (an operation), push it onto the stack,
Read - (an operation), push it onto the stack,
Read 4 (a number), the top of the stack is not a number, so push it onto the stack.
Read 2 (a number), the top of the stack is a number, so pop from the stack twice, you get 4 - 2, calculate it (2), and push the result (2) onto the stack.
Read 5 (a number), the top of the stack is a number, so pop from the stack twice, you get 2 * 5, push the result (10) onto the stack.
Read 3 (a number), the top of the stack is a number, so pop from the stack twice, you get 3 + 10, push the result (13) onto the stack.
Nothing left to read, pop from the stack and return the result (13).
Actual code:
#include <stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 102
typedef struct
{
char stk[MAXSIZE];
int top;
}STACK;
typedef struct stack
{
int stk[MAXSIZE];
int itop;
}INT_STACK;
STACK s;
INT_STACK a;
void push(char);
char pop(void);
void display(void);
int main()
{
a.itop = 0;
char string[MAXSIZE],vyb,vyb2;
int cislo1,cislo2,vysledok;
while (gets(string) != NULL){
for(int j = strlen(string); j > 0; j--){
if(string[j] == '*' || string[j] == '/' || string[j] == '+' || string[j] == '-')
push(string[j]);
}
//display();
for(int j = 0; j < strlen(string); j++){
if(isdigit(string[j])&&!(a.itop)){
//display();
char pomoc[2];
pomoc[0] = string[j];
pomoc[1] = '\0';
int_push(atoi(pomoc));
}
else if(isdigit(string[j])&&(a.itop)){
cislo1 = int_pop();
vyb2 = pop();
char pomoc[2];
pomoc[0] = string[j];
pomoc[1] = '\0';
cislo2 = atoi(pomoc);
if(vyb2 == '+')
vysledok = cislo1+cislo2;
else if(vyb2 == '-')
vysledok = cislo1-cislo2;
else if(vyb2 == '*')
vysledok = cislo1*cislo2;
else if(vyb2 == '/')
vysledok = cislo1 / cislo2;
//printf(" v %d",vysledok);
int_push(vysledok);
}
}
printf("%d\n",int_pop());
}
}
/* Function to add an element to the stack */
void push (char c)
{
s.top++;
s.stk[s.top] = c;
//printf ("pushed element is = %c \n", s.stk[s.top]);
}
/* Function to delete an element from the stack */
char pop ()
{
char num = s.stk[s.top];
// printf ("poped element is = %c\n", s.stk[s.top]);
s.top--;
return(num);
}
int empty()
{
if (s.top == - 1)
{
printf ("Stack is Empty\n");
return (s.top);
}
return 1;
}
void display ()
{
int i;
if (!empty)
{
printf ("Stack is empty\n");
return;
}
else
{
printf ("\n The status of the stack is \n");
for (i = s.top; i >= 0; i--)
{
printf ("%c\n", s.stk[i]);
}
}
printf ("\n");
}
void int_push (int c)
{
a.itop++;
a.stk[a.itop] = c;
//printf ("pushed element is = %d \n", a.stk[a.itop]);
}
/* Function to delete an element from the stack */
int int_pop ()
{
int num = a.stk[a.itop];
// printf ("poped element is = %d\n", a.stk[a.itop]);
a.itop--;
return(num);
}
Is there any other way to create a calculator with priority, which can give good answers?
Thanks for your respond
Put breakpoints - you'll get the following expression:
+ + * 2 5 2 5. The problem with that, is your interpreter is interpeting this as (2+5+2)*5 instead of (2+5) * (2+5).
Well then, you might be wondering how to solve this. There's no simple single solution - you could either fix your own interpreter or build a whole new mechanic, because the way you build expressions just can't handle more then one pair of parthesises.
For example, you may want to calculate all the values in parnthesises before even building the expression seperatley, possibly using recursion in the case of parenthesiseception - however if you actually choose to use that method, you might want to change the way you work with the expressions entirely, because that's a different approach.
If you need me to show actual code examples to explain this further using parts of the code you made, just ask for it and i'll edit and provide what you need.
Either way, I really advise you to look up working with interpreters in general - you could really learn a lot about analysing strings and working with different inputs, and people even did similar stuff to yours with calculators before
EDIT: you asked for examples, so here you go - this is an example of a completely different method using recursion. This way, you handle a single pair of parenthesises at a time, and thus you won't have the problem you currently do. Note - the source i'm basing this on ( pretty much copy-pasted with edits from the thread and some personal comments ) is from codereview on stack exchange, you can see it here
if you're intrested.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void getInput(char * in) {
printf("> ");
fgets(in, 256, stdin);
}
int isLeftParantheses(char p) {
if (p == '(') return 1;
else return 0;
}
int isRightParantheses(char p) {
if (p == ')') return 1;
else return 0;
}
int isOperator(char p) {
if (p == '+' || p == '-' || p == '*' || p == '/') return p;
else return 0;
}
int performOperator(int a, int b, char p) {
switch(p) {
case '+': return a+b;
case '-': return a-b;
case '*': return a*b;
case '/':
if (b == 0) { printf("Can't divide by 0, aborting...\n"); exit(1); } // now we dont want the world to expload here do we.
return a/b;
default:
puts("Bad value in switch.\n"); // A replacement which was mentioned in the thread- better have a default response just in case something goes wrong.
break;
}
return 0;
}
char isDigit(char p) {
if (p >= '0' && p <= '9') return 1;
else return 0;
}
int charToDigit(char p) {
if (p >= '0' && p <= '9') return p - '0';
else return 0;
}
int isNumber(char * p) {
while(*p) {
if (!isDigit(*p)) return 0;
p++;
}
return 1;
}
int len(char * p)
{
return (int) strlen(p); // This was bugged in the source, so I fixed it like the thread advised.
}
int numOfOperands(char * p) {
int total = 0;
while(*p) {
if (isOperator(*p)) total++;
p++;
}
return total+1;
}
int isMDGRoup(char *p)
{
for(; *p; p++) // used to be a while loop in the source, but this is better imho. more readable, also mentioned on the thread itself.
{
if (!isDigit(*p) && *p != '/' && *p != '*') return 0;
}
return 1;
}
int getLeftOperand(char * p, char * l) {
// Grab the left operand in p, put it in l,
//and return the index where it ends.
int i = 0;
// Operand is part of multi-*/ group
if (isMDGRoup(p)) {
while(1) {
if (*p == '*' || *p == '/') break;
l[i++] = *p++;
}
return i;
}
// Operand is in parantheses (so that's how you write it! sorry for my bad english :)
if(isLeftParantheses(*p)) {
int LeftParantheses = 1;
int RightParantheses= 0;
p++;
while(1) {
if (isLeftParantheses(*p)) LeftParantheses++;
if (isRightParantheses(*p)) RightParantheses++;
if (isRightParantheses(*p) && LeftParantheses == RightParantheses)
break;
l[i++] = *p++;
}
// while (!isRightParantheses(*p)) {
// l[i++] = *p++;
// }
l[i] = '\0';
return i+2;
}
// Operand is a number
while (1) {
if (!isDigit(*p)) break;
l[i++] = *p++;
}
l[i] = '\0';
return i;
}
int getOperator(char * p, int index, char * op) {
*op = p[index];
return index + 1;
}
int getRightOperand(char * p, char * l) {
// Grab the left operand in p, put it in l,
//and return the index where it ends.
while(*p && (isDigit(*p) || isOperator(*p) ||
isLeftParantheses(*p) || isRightParantheses(*p))) {
*l++ = *p++;
}
*l = '\0';
return 0;
}
int isEmpty(char * p) {
// Check if string/char is empty
if (len(p) == 0) return 1;
else return 0;
}
int calcExpression(char * p) {
// if p = #: return atoi(p)
//
// else:
// L = P.LeftSide
// O = P.Op
// R = P.RightSide
// return PerformOp(calcExpression(L), calcExpression(R), O)
// ACTUAL FUNCTION
// if p is a number, return it
if (isNumber(p)) return atoi(p);
// Get Left, Right and Op from p.
char leftOperand[256] = ""; char rightOperand[256]= "";
char op;
int leftOpIndex = getLeftOperand(p, leftOperand);
int operatorIndex = getOperator(p, leftOpIndex, &op);
int rightOpIndex = getRightOperand(p+operatorIndex, rightOperand);
printf("%s, %c, %s", leftOperand, op, rightOperand);
getchar();
if (isEmpty(rightOperand)) return calcExpression(leftOperand);
return performOperator(
calcExpression(leftOperand),
calcExpression(rightOperand),
op
);
}
int main()
{
char in[256];
while(1) {
// Read input from user
getInput(in);
if (strncmp(in, "quit", 4) == 0) break;
// Perform calculations
int result = calcExpression(in);
printf("%d\n", result);
}
}
I'm trying to check whether an array is sorted without using a loop. It's working properly, i,e. if I have an array with elements that are in ascending order, the printf executes, since I get "Sorted." But
printf("Array 1 returns: %d \n\n", sortCheck(arr1, SORTED1));
returns 0? Why is this?
Thanks. Here's the entire code.
#include<stdio.h>
const int SORTED1 = 5;
int sortCheck (int arr[], int arrSize);
int indexCounter = 0;
int main()
{
int arr1[] = {1,2,3,4,5};
printf("Array 1: \n");
printf("Array 1 returns: %d \n\n", sortCheck(arr1, SORTED1));
indexCounter = 0;
return 0;
}
int sortCheck(int arr[], int arrSize)
{
if ( (arr[indexCounter]==arr[arrSize-1]) && (indexCounter==arrSize-1) )
{
printf("Sorted. \n");
return 1;
}
if ( arr[indexCounter] <= arr[indexCounter+1] )
{
indexCounter++;
sortCheck(arr, arrSize);
}
else
{
printf("Not sorted.");
return 0;
}
}
You are seeing undefined behavior due to a missing return statement.
if ( arr[indexCounter] <= arr[indexCounter+1] )
{
indexCounter++;
// Problem. Missing return.
sortCheck(arr, arrSize);
}
Change the offending line to:
return sortCheck(arr, arrSize);
Following changes should print value 1
int sortCheck(int arr[], int arrSize)
{
int val = 0;
if ( (arr[indexCounter]==arr[arrSize-1]) && (indexCounter==arrSize-1) )
{
printf("Sorted. \n");
return 1;
}
if ( arr[indexCounter] <= arr[indexCounter+1] )
{
indexCounter++;
val = sortCheck(arr, arrSize);
return val;
}
else
{
printf("Not sorted.");
return 0;
}
}
the sortCheck() function does not check if the array is sorted.
there are two reasons for this.
1) when the recursive call was invoked, the returned value is being ignored, so the information about a particular byte pair is lost.
2) the index (arrSize) is always passed, rather than the offset to the current byte index
I.E. the whole sortCheck() function needs to be re-designed.
Using a debugger (or a printf( of the parameters) in the path that calls the recursive sortCheck() would have revealed that fact.