Perfect Numbers bug? - c

Currently I have this code, and it works.
#include <stdio.h>
int isFactor(long number1, long number2)
{
int isitFactor = (number2 % number1 == 0)?1:0;
return isitFactor;
}
int isPerfect(int number)
{
int counter;
int sum;
for (counter = 1; counter < number; counter++)
if (isFactor(counter, number))
sum += counter;
return (sum == number);
}
int main()
{
int counter = 1;
for (counter = 1; counter <= 100; counter++)
{
printf("", isPerfect(counter));
if (isPerfect(counter))
printf("%d\n", counter);
}
}
However, if I take out the unnecessary line with the printf in main(), it fails to produce any numbers.... Possible causes?!

Variable sum in function isPerfect is not initialized.

You had two problems with that code, the first is that sum is not initialised and will generally be set to whatever rubbish happened to be on the stack at the time the function was called. Automatic variables are not guaranteed to be initialised to zero (or anything, for that matter) so, if you need them to start with a specific value, you have to initialise them yourself.
The second problem (now fixed with your edit) was that isFactor is missing. Although you probably want it as a function, the following code works, producing the two perfect numbers less than 100, 6 and 28:
#include "stdio.h"
#define isFactor(c,n) ((n % c) == 0)
int isPerfect (int number) {
int counter;
int sum = 0; // <-- note initialisation here.
for (counter = 1; counter < number; counter++)
if (isFactor(counter, number)) sum += counter;
return (sum == number);
}
int main (void) { // try to use one of the two canonical forms.
int counter = 1;
for (counter = 1; counter <= 100; counter++)
if (isPerfect(counter)) printf("%d\n", counter);
return 0;
}
And, looking into why it might be working with that extra printf, here's a viable explanation.
When calling a function, the local variables are allocated on the stack simply by reducing the stack pointer. Your isPerfect asembly code probably just has a prolog like:
sub %esp,8
and then you use the memory at %esp for counter and %esp + 4 for sum. Without initialising sum, it starts with whatever happened to be at that memory location, which is probably not zero.
Now think about what happens when you call printf first. It no doubt has its own local variables so it uses the part of the stack that you will later be relying on to be initialised to zero. When the printf returns, it doesn't set those memory locations back to their previous values, it just increments the stack pointer to skip over them.
Then, when you call isPerfect, there's a good chance that those memory locations will be different to what they were before you called printf, simply because printf has been using them for its own purposes.
If you're lucky (or unlucky, depending on your viewpoint), the memory location where sum will be may even be zero. But it's undefined behaviour nonetheless and you should not rely on it - initialise sum explicitly and your (immediate) problems will be over.
If this is homework, feel free to ignore this bit (in fact, actively ignore it since you may get caught out for plagiarism). This is how I would implement the isPerfect function as a first cut. It doesn't call functions to work out factors since, while they're generally quite fast, they're not without cost, and something that simple can be done in a single line of C anyway.
int isPerfect (int num) {
int i, left;
for (i = 1, left = num; i < num; i++)
if ((num % i) == 0)
left -= i;
return (left == 0);
}
There's no doubt it could be made faster but the return on investment drops away pretty quickly after a certain point.

Related

Do arrays in C have a maximum index size of 2048?

I've written a piece of code that uses a static array of size 3000.
Ordinarily, I would just use a for loop to scan in 3000 values, but it appears that I can only ever scan in a maximum of 2048 numbers. To me that seems like an issue with memory allocation, but I'm not sure.
The problem arises because I do not want a user to input the amount of numbers they intend to input. They should only input whatever amount of numbers they want, terminate the scan by inputting 0, after which the program does its work. (Otherwise I would just use malloc.)
The code is a fairly simple number occurrence counter, found below:
int main(int argc, char **argv)
{
int c;
int d;
int j = 0;
int temp;
int array[3000];
int i;
// scanning in elements to array (have just used 3000 because no explicit value for the length of the sequence is included)
for (i = 0; i < 3000; i++)
{
scanf("%d", &array[i]);
if (array[i] == 0)
{
break;
}
}
// sorting
for(c = 0; c < i-1; c++) {
for(d = 0; d < i-c-1; d++) {
if(array[d] > array[d+1]) {
temp = array[d]; // swaps
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
int arrayLength = i + 1; // saving current 'i' value to use as 'n' value before reset
for(i = 0; i < arrayLength; i = j)
{
int numToCount = array[i];
int occurrence = 1; // if a number has been found the occurence is at least 1
for(j = i+1; j < arrayLength; j++) // new loops starts at current position in array +1 to check for duplicates
{
if(array[j] != numToCount) // prints immediately after finding out how many occurences there are, else adds another
{
printf("%d: %d\n", numToCount, occurrence);
break; // this break keeps 'j' at whatever value is NOT the numToCount, thus making the 'i = j' iterator restart the process at the right number
} else {
occurrence++;
}
}
}
return 0;
}
This code works perfectly for any number of inputs below 2048. An example of it not working would be inputting: 1000 1s, 1000 2s, and 1000 3s, after which the program would output:
1: 1000
2: 1000
3: 48
My question is whether there is any way to fix this so that the program will output the right amount of occurrences.
To answer your title question: The size of an array in C is limited (in theory) only by the maximum value that can be represented by a size_t variable. This is typically a 32- or 64-bit unsigned integer, so you can have (for the 32-bit case) over 4 billion elements (or much, much more in 64-bit systems).
However, what you are probably encountering in your code is a limit on the memory available to the program, where the line int array[3000]; declares an automatic variable. Space for these is generally allocated on the stack - which is a chunk of memory of limited size made available when the function (or main) is called. This memory has limited size and, in your case (assuming 32-bit, 4-byte integers), you are taking 12,000 bytes from the stack, which may cause problems.
There are two (maybe more?) ways to fix the problem. First, you could declared the array static - this would make the compiler pre-allocate the memory, so it would not need to be taken from the stack at run-time:
static int array[3000];
A second, probably better, approach would be to call malloc to allocate memory for the array; this assigns memory from the heap - which has (on almost all systems) considerably more space than the stack. It is often limited only by the available virtual memory of the operating system (many gigabytes on most modern PCs):
int *array = malloc(3000 * sizeof(int));
Also, the advantage of using malloc is that if, for some reason, there isn't enough memory available, the function will return NULL, and you can test for this.
You can access the elements of the array in the same way, using array[i] for example. Of course, you should be sure to release the memory when you've done with it, at the end of your function:
free(array);
(This will be done automatically in your case, when the program exits, but it's good coding style to get used to doing it explicitly!)

I cant write this factorial codes

I have some problem with that. I am trying to learn C programming. Please help me
#include<stdio.h>
int main()
{
int a, factorial;
printf("Please enter a value :" );
scanf("%d", &a);
for (int i = 1; i<=a; i++)
{
a = (a - 1)*a;
}
printf("%d", factorial);
return 0;
}
Well in your code line a = (a - 1)*a; you actually changed your input for getting the factorial. It also will blow your loop. See your for loop will continue as long as your i is less than a, lets say you choose a=3 after first iteration the a itself will become 6, so the for loop will continue until it reach the integer limit and you will get overflow error.
What you should do?
First of all you should use a second variable to store the factorial result, you introduced it as factorial, the way that #danielku97 said is a good way to write a factorial since if you present 0 as input it will also give the correct result of 1. so a good code is:
factorial = 1;
for (int i = 1; i<=a; i++)
{
factorial *= i;
}
But lets say you insist of subtraction, the way you just tried to use, then you need to change the code like:
scanf("%d", &a);
if (a==1 || a==0){
printf("1");
return 0;
}
factorial = a;
for (int i = 1; i<a; i++)
{
factorial *= (a - i)*factorial;
}
You can see that the code just got unnecessarily longer. An if included to correct the results for 1 and 0. Also you need to make sure that i never become like i =a since in that case a-i will be equal to zero and will make the factorial result equal to zero.
I hope the explanations can help you on learning C and Algorithm faster.
Your for loop is using your variable 'a' instead of the factorial variable and i, try something like this
factorial = 1;
for (int i = 1; i<=a; i++)
{
factorial *= i;
}
You must initialize your factorial to 1, and then the for loop will keep multiplying it by 'i' until 'i' is greater than 'a'.
You are modifying the input a rather than factorial and also wrong (undefined behaviour) because you are using factorial uninitialized. You simply need to use the factorial variable you declared.
int factorial = 1;
...
for (int i = 1; i<=a; i++) {
factorial = i*factorial;
}
EDIT:
Also, be aware that C's int can only hold limited values. So, beyond a certain number (roughly after 13! if sizeof(int) is 4 bytes), you'll cause integer overflow.
You may want to look at GNU bugnum library for handling large factorial values.

Is it cheating to use 'static' when writing a recursive algorithm?

As part of a programming assignment, I'm required to write a recursive function which determines the largest integer in an array. To quote the exact task:
Write a recursive function that finds the largest number in a given list of
integers.
I have come up with two solutions, the first of which makes two recursive calls:
int largest(int arr[], int length){
if(length == 0)
return 0;
else if(arr[length - 1] > largest(arr,length -1))
return arr[length];
else return largest(arr,length -1);
}
The second one makes only one, however it uses a static variable n:
int largest(int arr[], int length){
static int n = -1;
if(length == 0)
return n;
else if (arr[length - 1] > n)
n = arr[length - 1];
return largest(arr, length - 1);
}
I was wondering whether it would be considered cheating use static variables for such a task. Either way, which one is considered better form? Is there a recursive method which tops both?
I wouldn't say that it's cheating to use static variables this way - I'd say that it's incorrect. :-)
Imagine that you call this function multiple times on a number of different arrays. With the static variable introduced, the value of n never resets between calls, so you may end up returning the wrong value. Generally speaking, it's usually poor coding style to set things up like this, since it makes it really easy to get the wrong answer. Additionally, if your array contains only negative values, you may return -1 as the answer even though -1 is actually bigger than everything in the array.
I do think that the second version has one nice advantage over the first - it's much, much faster because it makes only one recursive call rather than two. Consider using the first version, but updating it so that you cache the value returned by the recursive call so that you don't make two calls. This will exponentially speed up the code; the initial version takes time Θ(2n), while the updated version would take time Θ(n).
There is nothing cheating using a static inside function, recursive or otherwise.
There can be many good reasons for why to do so, but in your case I suspect that you are coming up with a wrong solution -- in as largest will only work once in the lifetime of the program running it.
consider the following (pseudo) code;
main() {
largest([ 9, 8, 7]) // would return 9 -- OK
largest([ 1, 2, 3]) // would return 9 ?? bad
}
The reason being that your largest cannot tell the difference between the two calls, but if that is what you want then that is fine.
Edit:
In answer to your comment, something like this will have a better big-O notation than your initial code;
int largest(int arr[], int length){
int split, lower,upper;
switch (length) {
case 1: return arr[0];
case 2: if (arr[1]>arr[0]) return arr[1]; else return arr[0];
default:
if (len <= 0) throw error;
split = length/2;
lower = largest(arr,split);
upper = largest(arr+split,length-split);
if (lower > upper) return lower; else return upper;
}
}
Alternatively, the obvious solution is;
int largest(int arr[], int length){
if (length <= 0) thor error;
int max = arr[0];
for (int i=1; i<length; i++)
if (arr[i] > max) max = arr[i];
return max;
}
which has no recursion at all
It is actually a terrible design, because on the second execution of the function does not return a correct result.
I don't think you need to debate whether it is cheating, if it is wrong.
The first version is also incorrect, because you return arr[length] instead of arr[length-1]. You can eliminate the second recursive call. What can you do instead of calling the same function (with no side-effects) twice with the same arguments?
In addition to the excellent points in the three prior answers, you should practice having more of a recursion-based mind. (1) Handle the trivial case. (2) For a non-trivial case, make a trivial reduction in the task and recur on the (smaller) remaining problem.
I propose that your proper base case is a list of one item: return that item. An empty list has no largest element.
For the recursion case, check the first element against the max of the rest of the list; return the larger. In near-code form, this looks like the below. It makes only one recursive call, and has only one explicit local variable -- and that is to serve as an alias for the recursion result.
int largest(int arr[], int length){
if(length == 1)
// if only one element, return it
return arr[0];
else n = largest(arr,length-1))
// return the larger of the first element or the remaining largest.
return arr[length-1] > n ? arr[length-1] : n
}
Is there a recursive method which tops both?
Recursion gets a bad name when with N elements cause a recursion depth of N like with return largest(arr,length -1);
To avoid this, insure the length on each recursion is halved.
The maximum recursive depth is O(log2(N))
int largest(int arr[], int length) {
if (length <= 0) return INT_MIN;
int big = arr[0];
while (length > 1) {
int length_r = length / 2;
int length_l = length - length_r;
int big_r = largest(&arr[length_l], length_r);
if (big_r > big) big = big_r;
length = length_l;
}
return big;
}
A sneaky and fast method that barely uses recursion as finding the max is trivial with a loop.
int largest(int arr[], int length) {
if (length <= 0) return INT_MIN;
int max = largest(NULL, -1);
while (length) {
length--;
if (arr[length] > max) max = arr[length];
}
return max;
}

C array corrupted after calling a function

I have a simple C program which is supposed to fill an array with random values (this is the beginning of a school assignment). I'm using rand(), seeding it with srand(time()). Because this tended to generate somewhat predictable results when run repeatedly in a certain time period, I made another very simple function to give me a somewhat more random seed value:
time_t getRandomSeed(int numberOfIterations)
{
int i;
time_t result=time();
for (i = 0; i < numberOfIterations; i++)
{
result = randomizeSeed(result);
}
return result;
}
time_t randomizeSeed(time_t seed)
{
time_t result, fullTime, Modifier1, Modifier2;
srand((unsigned int)seed);
fullTime = time();
Modifier1 = time() >> (rand() % 10);
Modifier2 = (unsigned short)time();
Modifier2 <<= (rand() % 9 + 9);
result = fullTime ^ Modifier1 ^ Modifier2;
return result;
}
In main, I'm calling this inside srand() after declaring 2 int arrays. When I return to main, these arrays are garbage, and I can't figure out why.
int main(void)
{
int randomNumbers[ARRAY_LENGTH];
int sortedNumbers[ARRAY_LENGTH];
srand((unsigned int)getRandomSeed(2));
fillArray(randomNumbers, sizeof(randomNumbers) / sizeof(randomNumbers[0]));
return 0;
}
I set a breakpoint at line 4, and I have a perfectly normal unititialized array (at 0x00e1ea70 in the most recent run). Then I set another breakpoint at line 8, so I could see the array just before it was passed into fillArray. At this point, the address of the array is somehow 0xfffff04c, and all the elements show "unable to read memory", which I guess makes sense given the address is garbage.
Can anybody give me a clue what's happening to my array?
*Note, this is for a school assignment, so I don't really care if the RNG is secure, nor can I use any 3rd party libraries.
Update:
Per request, this is the body of fillArray(). However, from my question, the problem happens before we ever get to fillArray(), as I'm setting the breakpoint before it get's called.
void fillArray(int array[], size_t length)
{
size_t i;
for (i = 0; i < length; i++)
{
array[i] = rand()%1000 + 1;
}
return;
}
In your function randomizeSeed() you are calling time() three times in succession without an argument.
fullTime = time();
Modifier1 = time() >> (rand() % 10);
Modifier2 = (unsigned short)time();
The function prototype is
time_t time(time_t *timer);
So you should pay attention to your compiler warnings. From this point on, you have Undefined behaviour.

rand() returns nothing but zeroes

I am trying to write a program that will assign 5 random integers to an array but so far it is filling the array with zeroes. Also, the first number can't be a zero. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
int number[5];
int main() {
int i;
int t=0;
for (int t=0;t<5;t++) {
if (i=0)
{number[i] = rand()%8+1;}
else
{number[i] = rand()%10;}
i++;
printf("%d", number[i]);
}
return (0);
}
if (i=0)
That's assignment, not equality comparison.
int i;
Also, i is uninitialized, so accessing its value is undefined behavior. Since you accidentally assigned to it instead of comparing to it, if (i=0) doesn't invoke undefined behavior, but it would if you fixed the first bug.
i++;
printf("%d", number[i]);
Incrementing i before the print means you always print the cell right after the one you were working on.
You don't actually need i; t does everything you want i to do. We'll remove i and rename t to i:
for (int i = 0; i < 5; i++) {
if (i == 0) {
number[i] = rand() % 8 + 1;
} else {
number[i] = rand() % 10;
}
printf("%d", number[i]);
}
Several things are wrong in your code ...
1)
You didn't initialize the variable i
2)
if(i=0)
should be
if( i == 0 )
3)
You can use variable t instead of i -- means variable i is unnecessary
4)
You should have a function call for randomize() function before rand() function call, so that you can get the real random numbers
5)
If you just want to show the random numbers, you don't even need to use array
You will get the same sequence of 'pseudo-random' values by calling rand() in your program. To change this sequence the Random Number generator has to be 'seeded'. This is done by calling srand() function once with a seed value at the beginning of your program.
Ideally the value used for seed should change with each run of the program. Things that you could use as the seed are the process id, time, date or any other system provided value that is guaranteed to be different for each run of the program.
void srand(unsigned int seed);
Apart from that there are logical flaws in your program as others have highlighted, of which the if conditional assignment error is the most serious.

Resources