The program finds the average length of words in a given input and prints the words greater than the average. Here's the program
#define STRING_LEN 80
#define ARRAY_LEN 3
void *emalloc(size_t s) {
void *result = malloc(s);
if (NULL == result) {
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
return result;
}
void numbers_greater(char **wordlist, int average, int n){
if(n < ARRAY_LEN){
int a = strlen(wordlist[n]);
if(a>average){
printf("%s", wordlist[n]);
}
numbers_greater(wordlist+1, average, n+1);
}
}
int main(void) {
char word[STRING_LEN];
char *wordlist[ARRAY_LEN];
int num_words;
double average;
int i;
while (num_words < ARRAY_LEN && 1 == scanf("%79s", word)) {
wordlist[num_words] = emalloc((strlen(word) + 1) * sizeof wordlist[0][0]);
strcpy(wordlist[num_words], word);
num_words++;
}
average = 0.0;
for (i = 0; i < num_words; i++) {
average += strlen(wordlist[i]);
}
average = average / num_words;
printf("%f\n", average);
numbers_greater(wordlist, average, 0);
for (i = 0; i < num_words; i++) {
free(wordlist[i]);
}
return EXIT_SUCCESS;
}
The program works up until the "numbers_greater" method, giving a segmentation fault error. I'm new to C so I'm a little bit confused, the recursive method runs without an error without the strlen statement, but with the strlen statement (even if I set it to a static number like 2) it bombs out of the code. Am I traversing through the array incorrectly?
This line
numbers_greater(wordlist+1, average, n+1);
will increment both the wordlist pointer and the integer n. What you are doing, in effect is incrementing the value you are checking by 2 instead of by one, as you would like to do.
To eliminate the segfault, change this line to the following:
numbers_greater(wordlist, average, n + 1);
As a note, this could be done much easier using a simple for loop. Also, I did not read the rest of the code and there may be some other error that I missed, but this should eliminate the segmentation fault in this function.
Lets walk through
void numbers_greater(char **wordlist, int average, int n){
if(n < ARRAY_LEN){
int a = strlen(wordlist[n]);
if(a>average){
printf("%s", wordlist[n]);
}
numbers_greater(wordlist+1, average, n+1);
}
}
I have an array of strings that can hold 3 things, and I put n = 1. It works the first time... but now we get to
numbers_greater(wordlist+1, average, n+1);
so now we have an array of strings that can hold 2 things because of the wordlist+1 . n = 2 now , so n < ARRAY_LEN is true, but wordlist[n] will result in reading the 3rd element inside an array that should only hold 2.
To fix this try
numbers_greater(wordlist, average, n+1);
Related
Am I freeing memory correctly in this program with just free(lineArr) at the end of main()?
I still can't figure out what's causing the issue with all the chars in my output (image attached). I know it's probably something basic with how I have the for loops set up.. things print correctly the first run after compiling, but not the second run. Why would this be?
Thanks
// When the sum of proper divisors for a number is the same as the number
// itself, the "status" of that sum may be considered "perfect"; when less,
// "deficient", and when greater than, "abundant".
//
// This program takes two extra command-line arguments after the executable
// name: an integer and a character. The integer will be the number of
// numbers past 2 to print statuses and histogram bars for; the character
// will be used to construct a histogram bar with height = to the sum of
// divisors for a particular number. Example arguments: ./a.out 6 '*'
// Example output:
// 2 is Deficient *
// 3 is Deficient *
// 4 is Deficient ***
// 5 is Deficient *
// 6 is Perfect ******
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int sumOfDivisiors(int aNum); //prototype for sumOfDivisiors function
typedef struct{ //define a structure called "line" with three members
int lineNum;
int sum;
char status[10];
}line;
int main(int argc, char *argv[]){ //main will accept command line arguments
int howMany;
char usrChar;
line whichLine;
if(argc < 3){
printf("Error: must enter 3 command line arguments.\n");
exit(1);
}
sscanf(argv[1],"%d", &howMany);
sscanf(argv[2], "%c", &usrChar);
line** lineArr = malloc(howMany * sizeof(line*)); //allocate mem for array of struct ptrs
if (lineArr == NULL){
printf("Error: trouble allocating memory. Exiting.\n");
exit(1);
}
for (int n = 2; n <= howMany; n++){ //loop to call func + initialize lineNum, sum, status for current line
int sumResult = sumOfDivisiors(n);
lineArr[n] = malloc(sizeof(line)); //allocate mem for pointer to current line struct
if (lineArr[n] == NULL){
printf("Error: trouble allocating memory. Exiting.\n");
exit(1);
}
line* temp = lineArr[n];
temp->lineNum = n;
temp->sum = sumResult;
if (temp->sum == n){
strcpy(temp->status, "Perfect");
} else if (temp->sum < n){
strcpy(temp->status, "Deficient");
} else {
strcpy(temp->status, "Abundant");
}
}
for (int i = 2; i <= howMany; i++){ //loop to print formatted results
printf("%3d %-10s ", i, lineArr[i]->status);
for (int j = 0; j < lineArr[i]->sum; j++){
printf("%c", usrChar);
}
printf("\n");
}
free(lineArr); //free dynamically allocated memory
return 0;
}
//Definition for sumOfDivisiors function. This function accepts an int number
//as an argument. It takes that number, finds all proper divisors (divisors
//less than the number itself), then returns the integer result of adding
//up all these divisors.
int sumOfDivisiors(int aNum){
int result = 0;
int i;
for (i = 2; i <= sqrt(aNum); i++){
if (aNum % i == 0){
if (i == (aNum/i)){
result += i;
} else {
result += (i + aNum/i);
}
}
}
return(result + 1);
}
My code:
#include <stdio.h>
int main()
{
int count = 0;
int size = 0;
float num[size];
int i = 0;
float avg = 0;
float sum = 0;
while (scanf("%f",&num) != EOF)
{
if ((num[i] != num[i+1]) && (num[i] != num[i-1]))
{
sum = sum + num[i];
size++;
}
}
avg = sum/size;
printf("%0.2f", avg);
}
My input and output:
//input
2
2
1
^Z
//output
1.67
Correct input and output:
2 2 1
^Z
1.50
My question:
1) How can I make my code prompt input of numbers all on one line separated with spaces in between each input? Right now, my code always starts a new line after entering a number.
2) How can I fix my code so that it only calculates the average of non-repeated numbers? (NOTE: my code has to run no slower than O(nlogn). ) So I can't use nested loops as it will then have a run time of O(n^2).
You have some problems in your code:
the usage of num
test on scanf
the test of already used number.
the usage of num
When you write
int size = 0;
float num[size];
You do not allocate memory to store numbers.
and
while (scanf("%f",&num) != EOF)
Is not correct since you are not storing the value read into a float: gcc warns:
warning: format ‘%f’ expects argument of type ‘float *’, but argument 2 has type ‘float (*)[(sizetype)(size)]’ [-Wformat=]
A more correct way to do would be to write:
float num;
...
while (scanf("%f",&num) != EOF)
test on scanf
You test that scanf does not return EOF, but what if your conversion failed if you do not give a number?
The correct way to test what the user gives, is to check that you have the number of conversion wanted:
while (scanf("%f",&num) == 1)
the test of already used number.
Writting
if ((num[i] != num[i+1]) && (num[i] != num[i-1]))
You test last number (i) against past and future number (?!)
You have a simplier approch: have an array to store the already got number. This imply to have a function to test a number has already been got.
Warning The current implementation of is_number_in_array it very naive and make your program run in O(n). You can easyly replace it with some dichotomic search which is O(log n)
So a corrected version of your code could be:
#include <stdio.h>
int is_number_in_array(float num, float *array, int size)
{
for (int i =0; i < size; ++i)
{
if (num == array[i])
return 1;
}
return 0;
}
#define MAX_NUMBER 50
int main(void)
{
/* number of number read */
int size = 0;
/* number already read */
float array[MAX_NUMBER] = {};
/* currently read number */
float num = 0;
float avg = 0;
float sum = 0;
/* get next number, stop when a conversion failed */
while (scanf("%f",&num) == 1)
{
/* test if number is already in array */
if (! is_number_in_array(num, array, size )) {
/* not in array: add it */
array[size ++] = num;
sum += num;
}
/* Add some test here to check that size is not as big as MAX_NUMBER */
}
avg = sum/size;
printf("%0.2f", avg);
return 0;
}
First, read the numbers into an array nums. Let n be the number of numbers in the array. This can be done in O(N). I leave this to you.
Secondly, sort the array using a O(N log N) algorithm. I leave this to you.
Finally, we can identify duplicates by simply consulting neighbours. The tricky part is avoiding going out of bounds. Accessing nums[-1] or nums[n] would result in Undefined Behaviour, so we have to avoid that.
We don't need to look ahead and backwards. We want to use a number the first time we encounter it, so we only need to look backwards.
Don't forget to make sure we have at least one number, because we can't divide by zero.
if (!n) {
fprintf(stderr, "Can't find the average of zero numbers.\n");
exit(1);
}
float sum = 0;
size_t uniques = 0;
for (size_t i=0; i<n; ++i) {
if (i > 0 && nums[i] == nums[i-1])
continue;
sum += nums[i];
++uniques;
}
float avg = sum/uniques;
The complexity analysis is O(N + N log N + N) = O(N log N).
(Both of the other answers include O(N^2) solutions
As an aside, we can do better than O(N log N).
In practical terms, inserting into a well-written hash table has an amortized performance of O(1), and lookups are O(1). We can use this to devise an O(N) solution to the problem.
Using Perl, since it has such hash tables built-in:
#nums
or die("Can't find the average of zero numbers.\n");
my %seen; # Hash table.
my $sum = 0;
my $uniques = 0;
for my $num (#nums) {
next if $seen{$num}++;
$sum += $num;
++$uniques;
}
my $avg = $sum/$uniques;
This approach saves all integers in an array, as long they are not saved already, as to avoid duplicates.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int bytes_read;
int size = 1000;
int i = 0;
int amount = 0;
int number = 0;
// boolean flag to detect duplicate numbers.
int duplicate = 0;
int sum = 0;
float unique_avg = 0;
// Allocate char / int arrays on the heap.
// These can be resized with realloc() if needed.
char* string = (char *) malloc (size);
int* unique_num = (int *) calloc (2 * size, 0);
// Declare char pointers to be used will splitting the string.
char* token;
char* rest = string;
printf ("Please enter a string: ");
bytes_read = getline (&string, &size, stdin);
// In case getline fails to get the input.
if (bytes_read == -1) {
puts ("error!");
}
// getline() read input succesfully.
else {
// Iterate over all space separated string tokens.
while ((token = strtok_r(rest, " ", &rest))){
// Convert string token to number
number = atoi(token);
for(i = 0; i < 2 * size; ++i){
if(number == unique_num[i]){
// Duplicate found.
duplicate = 1;
break;
}
}
if(!duplicate){
unique_num[amount] = number;
++amount;
}
// Restore value of duplicate for next iteration
duplicate = 0;
}
}
// Sum all unique numbers.
for(i = 0; i < amount; ++i){
sum += unique_num[i];
}
// Calculate the avg of unique numbers.
// Float casting is required for the fractional part of the division.
unique_avg = (float) sum / (float) (amount);
// Print the average.
printf("%f", unique_avg);
return 0;
}
Running this code in console yields with example input of 2 2 1:
Please enter a string: 2 2 1
1.500000
Adding the printf("Hi!\n") statements allows the code to work. It also works if the bound initial bound is improper and the user enters a new one. When I ran some tests calculate divers sometimes returned a character instead of an integer. I'm thinking it has something to do with my memory allocation. I also noticed that ./a.out 6 10 "|" would work but ./a.out 6 25 "|" would not causing an infinite loop when printing the lines of "|".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Structs
typedef struct data_struct {
int lineNumber;
int divisorSum;
char type[10];
}data;
// Prototypes
int calculateDivsors(int integer);
// Functions
int main (int argc, char *argv[]) {
int lowerBound;
int upperBound;
char character;
// Gets the values from command-line
sscanf(argv[1], "%d", &lowerBound);
sscanf(argv[2], "%d", &upperBound);
sscanf(argv[3], "%c", &character);
// Check to see if bound is proper
while (upperBound <= lowerBound || lowerBound < 2) {
printf("Error, please enter a new range (positive increasing).\n");
scanf("%d %d", &lowerBound, &upperBound);
}
// Structure calls
data* info = NULL;
int totalData = upperBound - lowerBound;
// Allocate the memory
info = (data*)malloc(totalData * sizeof(data));
printf("Hi!\n");
if (info != NULL) {
// Iterate through all the digits between the two bounds
for (int i = lowerBound; i <= upperBound; i++) {
int sum = calculateDivsors(i);
// Write data to indiviual structures
info[i].lineNumber = i;
info[i].divisorSum = sum;
// Check to see if the sum is greater than, less than, or equal to the original
if (sum == i) {
strcpy(info[i].type, "Perfect");
}
else if (sum > i) {
strcpy(info[i].type, "Abundant");
}
else if (sum < i) {
strcpy(info[i].type, "Deficient");
}
// Line n# has a column width of 4, string of 10
printf("%4d is %-10s\t", info[i].lineNumber, info[i].type);
// Generate Pictogram
for (int j = 0; j < info[i].divisorSum; j++) {
printf("%c", character);
}
printf("\n");
}
}
}
// Adds up the sum of diviors
int calculateDivsors(int integer) {
int sum = 0;
for (int i = 1; i < integer; i++) {
// Add to sum if perfectly i is a sum of integer
if (integer % i == 0) {
sum += i;
}
}
return sum; // Returns the sum of diviors
}
You are accessing data outside its allocated buffer whenever lowerBound doesn't start with 0.
info[i].lineNumber = i;
Ideally, you should become...
info[i - lowerBound].lineNumber = i;
To ensure that the indexing starts at 0. Further, your window between lowerBound and upperBound is inclusive. That means it includes both ending boundaries. Therefore, totalData is undersized by one element. Even if you fix the indexing problem, your code will still be wrong with this:
int totalData = (upperBound - lowerBound) + 1;
Failing to do both of the above causes your code to invoke undefined behavior (UB), and thus unpredictable results thereafter. It may even appear to work. That, however, is a red herring when your code has UB. Don't confuse defined behavior with observed behavior. You can trust the latter only once you have the former; the two are not synonymous.
I am trying to understand how to find the maximum number using a recursive function, but I do not really understand how. Having this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ar[100],n,i;
int *ptr;
printf("Enter size of the list:");
scanf("%d", &n);
printf("Printing the list:\n");
for (i = 0; i < n ; i++)
{
scanf("%d", &ar[i]);
}
ptr=&ar;
int max=maximum(ptr,n);
printf("ma %d",max);
return 0;
}
int maximum(int ar[], int n)
{
int max;
if(n+1==1)
{
return ar[n];
}
max =maximum(ar,n-1);
return ar[n]>max?ar[n]:max;
}
What is it actually doing and how?
Is it correctly using pointers to point the array of integers?
I hope you can help me understand it!
You set aside memory for an array of 100 integers with int ar[100], and you enter n which is set using scanf("%d", &n). If you enter a number greater than 100 at this stage, your program will seg fault because your loop for (i = 0; i < n ; i++) will try to access ar[100] which is a memory access error (the highest array index available is ar[100 - 1], notice that 100 - 1 < 100). Anyways, you fill n indices of ar in the loop. ptr = &ar just assigns the starting address of ar to ptr. By the way ptr = ar will work too, the & is not necessary. Now you can use ptr the same way you were using ar.
The easiest way to understand the recursion is to go straight to the last call of maximum. But first, understand that you passed ptr to the function which is the same as passing ar (remember, they are the same thing in main since ptr = ar.).
So in the last call to maximum, When n + 1 == 1 (same as n == 0), it returns ar[n] which is ar[0], which is first the number you entered for 'Printing the list' (it was stored in ar[0]).
Now in the second last call to maximum, n + 1 == 1 is false because n = 1 so we go to max = maximum(ar, n - 1). That's the result of the last call to maximum that I just explained, so max has the value of ar[0]. Now you have return ar[n] > max ? ar[n] : max, which is the same as return ar[1] > ar[0] ? ar[1] : ar[0]. That is the same as
if (ar[1] > ar[0]) {
return ar[1];
} else {
return ar[0];
}
And you can see that this returns whichever is bigger, ar[0] or ar[1]. Now for the third last call to maximum, max is the result of the second last call to maximum. And you can see the pattern emerge. You will return whichever is greater: max or ar[n] for all the rest of the calls to maximum, and by the time you get to the first call to maximum, you will have compared all the values in ar to find its maximum and return it.
Also, what Ajay said is right, ar[n] is accessing a value that you never initialized in your loop. You should write int max = maximum(ptr, n - 1) in main to fix that.
My solution with tail recursion:
int maximum(int a[], int n)
{
if (n == 1)
return a[0];
--n;
return maximum(a + (a[0] < a[n]), n);
}
Demo on compiler explorer
To understand how maximum works, just try and find some invariants in the maximum function
int maximum(int ar[], int n)
{
int max;
if(n==0)
{
return ar[n];
}
max =maximum(ar,n-1);
/* at this point MAX keeps the maximum of the subarray [0..N-1] and using this
we try to get by induction the maximum of [1..N]. */
return ar[n]>max?ar[n]:max;
}
Consider that definition :
#include <stdio.h>
#include <stdlib.h>
void maximum(int nums[], int size, int index, int * max)
{
if (index != size) {
if (nums[index] > *max)
*max = nums[index];
maximum(nums, size, ++index, max);
}
}
int main()
{
int * nums;
int size, i, max;
fprintf(stderr, "Enter size of the list: "); /* stderr to flush without \n */
if ((scanf("%d", &size) != 1) || (size <= 0)) {
puts("wrong size");
return 0;
}
if ((nums = malloc(size * sizeof(int))) == 0) {
puts("cannot allocate nums");
return 0;
}
for (i = 0; i != size; ++i) {
if (scanf("%d", &nums[i]) != 1) {
puts("invalid number");
return 0;
}
}
max = nums[0];
maximum(nums, size, 1, &max);
free(nums);
printf("max = %d\n", max);
return 0;
}
Execution:
% gcc -O2 -pedantic -Wall m.c
% ./a.out
Enter size of the list: 3
3
1
2
max = 3
maximum is recursive, but this is a terminal recursion, so the compiler can remove it to generate a loop. So maximum seems to be recursive as you request but the stack will not explode even with a large number :
% ( echo 100000000 ; yes 1 ) | ./a.out
Enter size of the list: max = 1
If I remove the option -O2 the generate code uses the recursion and the stack explode :
% gcc -pedantic -Wall m.c
% ( echo 100000000 ; yes 1 ) | ./a.out
Enter size of the list: Segmentation fault
int maxRecursively( arr array, int index){
int max = array.ptr[index];
if ( index == array.length-2 ){
return max= array.ptr[index]> array.ptr[index+1] ? array.ptr[index]:array.ptr[index+1];
}
return max = max > maxRecursively(array,index+1) ? max: maxRecursively(array,index+1);
}
I am trying to make a program that calculates the amount of prime numbers that don't exceed an integer using the sieve of Eratosthenes. While my program works fine (and fast) for small numbers, after a certain number (46337) I get a "command terminated by signal 11" error, which I suppose has to do with array size. I tried to use malloc() but I didn't get it quite right. What shall I do for big numbers (up to 5billion)?
#include <stdio.h>
#include<stdlib.h>
int main(){
signed long int x,i, j, prime = 0;
scanf("%ld", &x);
int num[x];
for(i=2; i<=x;i++){
num[i]=1;
}
for(i=2; i<=x;i++){
if(num[i] == 1){
for(j=i*i; j<=x; j = j + i){
num[j] = 0;
}
//printf("num[%d]\n", i);
prime++;
}
}
printf("%ld", prime);
return 0;
}
Your array
int num[x];
is on the stack, where only small arrays can be accommodated. For large array size you'll have to allocate memory. You can save on memory bloat by using char type, because you only need a status.
char *num = malloc(x+1); // allow for indexing by [x]
if(num == NULL) {
// deal with allocation error
}
//... the sieve code
free(num);
I suggest also, you must check that i*i does not break the int limit by using
if(num[i] == 1){
if (x / i >= i){ // make sure i*i won't break
for(j=i*i; j<=x; j = j + i){
num[j] = 0;
}
}
}
Lastly, you want to go to 5 billion, which is outside the range of uint32_t (which unsigned long int is on my system) at 4.2 billion. If that will satisfy you, change the int definitions to unsigned, watching out that your loop controls don't wrap, that is, use unsigned x = UINT_MAX - 1;
If you don't have 5Gb memory available, use bit status as suggest by #BoPersson.
The following code checks for errors, tested with values up to 5000000000, properly outputs the final count of number of primes, uses malloc so as to avoid overrunning the available stack space.
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long int x,i, j;
unsigned prime = 0;
scanf("%lu", &x);
char *num = malloc( x);
if( NULL == num)
{
perror( "malloc failed");
exit(EXIT_FAILURE);
}
for(i=0; i<x;i++)
{
num[i]=1;
}
for(i=2; i<x;i++)
{
if(num[i] == 1)
{
for(j=i*i; j<x; j = j + i)
{
num[j] = 0;
}
//printf("num[%lu]\n", i);
prime++;
}
}
printf("%u\n", prime);
return 0;
}