I have to do as a school assigment small program in C that will read standart input and prints some standart output. To be more specific, it's about reading numbers and sorting them.
(you can skip this, it's just for understanding the code)
First line of the input should determine how many lines of numbers there will be. Second line is ammount of numbers in next line. Third line are to concrete numbers. Fourth line is ammount of numbers in next line and so on until it reaches K number of lines. Restrictions are 0 < K <= 10 (max 10 sequences), each sequence can contain max 10.000.000 numbers and each number's value is max 10.000.000
Example
Input:
2 //which means that there will be 2 sequences (lines) of numbers and their corresponding ammount
3 //in the first sequence there will be 3 numbers
5 99912 45 //first sequence
6 //in the second sequence there will be 6 numbers
9489498 22131 0 521313 7988956 5 //second sequence
Ouptup:
0 5 5 45 22131 99912 521313 7988956 9489498
So I have done a working program but it seems to be unstable with higher values. However I can't determine when and where exactly the program fails. On my computer, I have tested all possible max values and it returned correct output in reasonable time, but on a school server where tests are done it just can't handle high values and fails.
There is one thing, that the program should only use C, not C++, but I am not very sure of differences between them and as I was using C++ compiler, it's possible that my code isn't just raw C.
I am a C beginner and this is something like "Hello world" for me, so please, can you just quick look through the code and say what can cause the unstability? Thanks
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int k, n, i, y, x, index = 0;
int *numbers = (int*) malloc(100000000 * sizeof(int));
if(numbers == NULL){
exit(1);
}
scanf("%d", &k);
for (x = 0; x < k; x++) {
y = 0;
scanf("%d", &n);
while(scanf("%d", &i) > 0){
numbers[index++] = i;
if(++y == n){
break;
}
}
}
for(y = 0;y < index;y++){ //find and print all 0's, because later I will use 0 as a
//already used (printed) element in array and ignore it
if(numbers[y] == 0){
if(y == index-1){
printf("0");
}else{
printf("0 ");
}
}
}
int smallest, smallestIndex;
for(x = 0;x < index;x++){ //print all other numbers in ascending order
smallest = 0;
for(y = 0;y < index;y++){ //find current smallest number
if((numbers[y] < smallest || smallest == 0) && numbers[y] != 0){
smallest = numbers[y];
smallestIndex = y;
}
}
numbers[smallestIndex] = 0;
if(smallest > 0){
if(x == index-1){
printf("%d", smallest);
}else{
printf("%d ", smallest);
}
}
}
free(numbers);
numbers = NULL;
return 0;
}
Based on the information you give, I think this is simply a resource limitation on the server. The server simply runs out of memory and your malloc() fails. I suggest you debug or do this:
if(numbers == NULL){
printf("malloc() failed\n");
exit(1);
}
The code for printing the initial zeros is suspicious:
for(y = 0;y < index;y++){ //find and print all 0's, because later I will use 0 as a
//already used (printed) element in array and ignore it
if(numbers[y] == 0){
if(y == index-1){
printf("0");
}else{
printf("0 ");
}
}
Suppose you have a sequence with 0 as the last element (e.g. 1 2 3 4 5 0); i guess this code will print just 0 with no space after it, and the subsequent code will print 1 2 3 4 5, so you will get something like 01 2 3 4 5.
I understand that you want the output to be as beautiful as possible, that is, without a space at the end. Please also note that a newline (\n) at the end of output might be good.
I rewrote beginning parts of your program to get you on the right path. This should help you but I can't be sure since I don't really know what is causing your program to crash.
This implements the realloc function which should make your program drastically more efficient than it is now. If you don't know what realloc is you can read about it here, and here.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER 256 //for memory management
int main(void)
{
int k, n, i, y , x, index = 0, bff; //declare integer 'bff' and set it to BUFFER
int *numbers = NULL, *tmp; //declare a pointer (numbers) for allocated memory, and a pointer (tmp) for the realloc function
if(!(numbers = malloc(BUFFER * sizeof(int)))) //allocate space for 'bff' integers
{
exit(1); //allocation failed
}
scanf("%d", &k);
for (x = 0; x < k; x++)
{
scanf("%d", &n);
while(scanf("%d", &i) > 0)
{
if(bff <= index) //if the size of index grows larger than the amount of space we allocated
{
bff += BUFFER; //increase the size of bff by BUFFER
if(!(tmp = realloc(numbers, bff * sizeof(int)))) //resize our allocated memory block using the tmp pointer
{
free(numbers); //allocation failed so free already allocated memory
exit(1); //and terminate the program
}
numbers = tmp; //make numbers point to the same location as tmp
numbers[index++] = i;
if(++y == n) break;
}
}
}
.
.
.
free(numbers);
return 0;
}
Keep in mind there are more efficient ways to use realloc. I just posted this here to get you on the right track. Good luck!
You are allocating the wrong amount of memory. The specification states that each sequence can contain 10 million values whereas you allocate a fixed amount. There may be up to k*10 million values of input, and you cannot know that the amount you allocate is enough.
As pointed out by m0skit0, the problem may also be due to over-allocation.
To fix the problem you should allocate the needed amount of memory, no more, no less.
Use the sequence length provided for each sequence to do that.
Also, you need to check the return value of malloc and realloc. If the return value is NULL then the allocation failed and you should print an error message and exit.
Related
Well, I've written a code which basically does:
Asks for array length
User input the array into *p
longestNeg function checks the longest negative sequence.
What it has to do: Return the longest negative sequence with its values.
Problem: in the longestNeg function (throws exception)
if (*arr < 0) {
counter++;
}
Question: Why does it happen?
Question2: Will while (arr < arr + n) work?
Edit3:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
void longestNeg(int *arr, int n);
int main()
{
int *arr1, n,num = 0,*p;
printf("Please enter the size of the array: ");
scanf("%d", &n);
arr1 = (int*)malloc(n * sizeof(int));
if (arr1 == NULL)
printf("Not enough memory\n");
else printf("Array was allocated!\n" );
for (p = arr1; p < arr1 + n; p++)
{
scanf("%d", p);
}
longestNeg(p - n, n);
free(arr1);
getch();
}
void longestNeg(int *arr, int n)
{
int counter = 0, temp = 0, *p;
for (p = arr; p < arr + n; p++)
{
if (*p < 0) {
counter++;
}
else if (counter > temp) {
temp = counter;
counter = 0;
}
else
counter = 0;
}
if (counter != 0)
for (p = arr; p < arr + counter; p++)
{
printf("%d ", *p);
}
else
printf("No neg numbers.");
}
.....To count the negative numbers, you are incrementing arr past them while checking if they're negative and elapsing counter if so. You then try to print counter numbers from arr, which now points after the negative sequence.
So, just think about it. Imagine that you are a computer. The human has entered 1, 2, -1, -2, -3, -4, 3, 4. You count up - and increment past - the 4 negative numbers. Your pointer arr now points to the penultimate value, 3. The user then asks you to print counter == 4 values from this 3 onwards. But only 2 values are left that belong to the user's allocated region of memory - namely the last pair, 3 and 4.
By trying to use memory that doesn't belong to them, the user invokes undefined behaviour, and the program is perfectly within its rights to do absolutely anything (undefined behaviour) - including segfaulting as it appears to be on your system.
So, stop doing that. Either use a temporary copy of the passed-in pointer arr in your first or both while loops, or do your counting and printing in the same loop. It's really that simple.
Stepping through the problem as though you were the computer is not to be underestimated as a diagnostic tactic that can help you actually think about what you've programmed, if you haven't already.
Two problems: When the loop is done the pointer p points to one beyond the end of the allocated memory. And the second problem is the cause of your problem: You pass a pointer to the pointer to your function which expectes a pointer, leading to undefined behavior.
You should learn to always create function prototype declarations for all your functions, because then the compiler would have been able to catch it and print an error instead of just giving you a warning (which you should have gotten).
Here is a link to the problem I'm trying to solve: http://acm.timus.ru/problem.aspx?space=1&num=1086
Here is my approach:
#include <stdio.h>
#include <math.h>
int main()
{
int n, i, m, p;
scanf("%d", &n);
for(i = 0; i < n; i++)
{
scanf("%d", &m);
p = find_prime(m);
printf("%d\n", p);
}
return 0;
}
int find_prime(int a)
{
int i, p = 1, t, prime[15000], j;
prime[0] = 2;
for(i = 0; i < a; )
{
if(p == 2)
{
p++;
}else
{
p = p + 1;
}
t = 0;
for(j = 0; prime[j] <= sqrt(p); j++)
{
if(p%prime[j] == 0 && p != 2)
{
t = 1;
break;
}
}
if(t != 1)
{
i++;
prime[i] = p;
}
}
return p;
}
I know the algorithm is fine and it produces the correct answer. But I always get "Time Limit Exceeded". I can't get the runtime download to 2 seconds. It's always equal to 2.031 seconds. I have tried few other approaches, for example, I iterated through all the numbers until I found the mth prime number, I tried skipping the even integers greater than 2 but I still get 2.031 seconds.
What should I do?
Your buffer for prime numbers doesn't need to be a local variable that's recalculated every time.
You can try to memoize by storing the buffer in the global scope and using a global counter to keep track of how many primes you have already calculated until now and which number was the maximum number requested.
If the next number that's requested from you is smaller than the previous maximum, you should fall back to the corresponding pre-calculated number. If the next number is larger than the previous maximum, make it the new maximum - and also try to start calculating from where you last left off.
Remove
if(p == 2)
{
p++;
}else
{
p = p + 1;
}
and replace it with
p++
as I understand it,
the problem is to find the next prime greater that the sum of all the prior input numbers.
That means there are certain expectations.
1) the sum of the prior input numbers is available in find_prime().
2) for simplification, the last found prime number is available in find_prime().
Neither of these expectations are implemented.
Then there is that 60 thousand byte array on the stack in find_prime().
Suggest moving that to a file global position and including a 'static' modifier.
move the prior sum of inputs to a file global location, so it is always available.
for overall speed,
calculate all the primes in the array as a first thing, thereby filling the array with prime values. then
1) add new input to sum,
2) index into array using sum.
3) return value found in array.
This question already has answers here:
Get the number of elements that it has a value in array
(3 answers)
Closed 8 years ago.
I have this code:
int main() {
int array[5];
int x;
int n;
for(x = 0; x != 5; x++) {
scanf("%d", &n);
if(n % 2 == 0) {
array[x] = n;
}
printf("%d", sizeof(array))
I'd like to know how many variable are saved in the array.
Given that the user entered "2, 3, 5, 6, 7, 8" and it would only get "2,6,8", is there any way to get the size of that?
One way I could do this is to make another int:
int main() {
int array[5];
int x;
int g = 0;
int n;
for(x = 0; x != 5; x++) {
scanf("%d", &n);
if(n % 2 == 0) {
array[x] = n;
g++;
}
printf("%d", g);
Is there any way to do this without incrementing g inside the if block?
You must keep track of the count, or else you won't know what index to use for the array. Your current code doesn't work because you're leaving gaps in the array between the even numbers:
for (x = 0; x != 5; x++) {
scanf("%d", &n);
if (n % 2 == 0) {
array[x] = n;
g++;
}
For the input "2 3 5 6 7", you are storing the number 2 at position 0 in the array, and the number 6 at position 3. At the other positions there is random data. They aren't even zero values because you declared the array inside a function. By the way, a fixed-size array should be declared in the global scope, outside any function. That's because variables inside a function are allocated in a stack frame, which is a small and transient piece of memory. You want your arrays on the heap, which is big and long-lived.
The following code contains several improvements. It defines a constant for the length of the array, and checks the current count before saving a number. (Bad things happen if you write beyond the end of an array.) Also, this code imposes no fixed limit on the amount of data it will read. It keeps calling scanf until the end-of-file value, EOF, is returned.
#include <stdio.h>
#include <stdlib.h>
#define MAX_COUNT 1000
int even[MAX_COUNT];
int main() {
int x,
count = 0; /* Track the number of even numbers. */
while (scanf("%d", &x) != EOF) { /* Get an integer from standard input. */
if(x % 2 == 0) { /* Is it even? */
if (count == MAX_COUNT) { /* If so, check the count first. */
printf("I have reached the limit of %d! I cannot store %d.",
MAX_COUNT, x); /* Fail gracefully if the array is */
} else { /* full. Otherwise, we can go */
even[count++] = x; /* ahead and save the number. */
}
}
}
printf("There are %d even numbers.\n", count);
return 0;
}
You need to keep track of this yourself.
Perhaps by using an extra variable (as you show in your second example), or by having a sentinel value that you can count up to (like how we use the null character in strings)
I am participating in Harvard's opencourse ware and attempting the homework questions. I wrote (or tried to) write a program in C to sort an array using bubble sort implementation. After I finished it, I tested it with an array of size 5, then 6 then 3 etc. All worked. then, I tried to test it with an array of size 11, and then that's when it started bugging out. The program was written to stop getting numbers for the array after it hits the array size entered by the user. But, when I tested it with array size 11 it would continuously try to get more values from the user, past the size declared. It did that to me consistently for a couple days, then the third day I tried to initialize the array size variable to 0, then all of a sudden it would continue to have the same issues with an array size of 4 or more. I un-did the initialization and it continues to do the same thing for an array size of over 4. I cant figure out why the program would work for some array sizes and not others. I used main to get the array size and values from the keyboard, then I passed it to a function I wrote called sort. Note that this is not homework or anything I need to get credit, It is solely for learning. Any comments will be very much appreciated. Thanks.
/****************************************************************************
* helpers.c
*
* Computer Science 50
* Problem Set 3
*
* Helper functions for Problem Set 3.
***************************************************************************/
#include <cs50.h>
#include <stdio.h>
#include "helpers.h"
void
sort(int values[], int n);
int main(){
printf("Please enter the size of the array \n");
int num = GetInt();
int mystack[num];
for (int z=0; z < num; z++){
mystack[z] = GetInt();
}
sort(mystack, num);
}
/*
* Sorts array of n values.
*/
void
sort(int values[], int n)
{
// this is a bubble sort implementation
bool swapped = false; // initialize variable to check if swap was made
for (int i=0; i < (n-1);){ // loops through all array values
if (values[i + 1] > values [i]){ // checks the neighbor to see if it's bigger
i++; // if bigger do nothing except to move to the next value in the array
}
else{ // if neighbor is not bigger then out of order and needs sorting
int temp = values[i]; // store current array value in temp variable for swapping purposes
values[i] = values[i+1]; //swap with neighbor
values[i+1] = temp; // swap neighbor to current array value
swapped = true; // keep track that swap was made
i++;
}
// if we are at the end of array and swap was made then go back to beginning
// and start process again.
if((i == (n-1) && (swapped == true))){
i = 0;
swapped = false;
}
// if we are at the end and swap was not made then array must be in order so print it
if((i == (n-1) && (swapped == false))){
for (int y =0; y < n; y++){
printf("%d", values[y]);
}
// exit program
break;
}
} // end for
// return;
}
You can easily use 2 nested for loops :
int i, j, temp ;
for ( i = 0 ; i < n - 1 ; i++ )
{
for ( j = 0 ; j <= n - 2 - i ; j++ )
{
if ( arr[j] > arr[j + 1] )
{
temp = arr[j] ;
arr[j] = arr[j + 1] ;
arr[j + 1] = temp ;
}
}
}
also you should now it's a c++ code not a c, because c doesn't have something like :
int mystack[num];
and you should enter a number when you're creating an array and you can't use a variable (like "int num" in your code). This is in C, but in C++ you're doing right.
The first thing to do when debugging a problem like this is ensure that the computer is seeing the data you think it should be seeing. You do that by printing out the data as it is entered. You're having trouble with the inputs; print out what the computer is seeing:
static void dump_array(FILE *fp, const char *tag, const int *array, int size)
{
fprintf(fp, "Array %s (%d items)\n", tag, size);
for (int i = 0; i < size; i++)
fprintf(fp, " %d: %d\n", i, array[i]);
}
int main(void)
{
printf("Please enter the size of the array \n");
int num = GetInt();
printf("num = %d\n", num);
int mystack[num];
for (int z = 0; z < num; z++)
{
mystack[z] = GetInt();
printf("%d: %d\n", z, mystack[z]);
}
dump_array(stdout, "Before", mystack, num);
sort(mystack, num);
dump_array(stdout, "After", mystack, num);
}
This will give you direct indications of what is being entered as it is entered, which will probably help you recognize what is going wrong. Printing out inputs is a very basic debugging technique.
Also, stylistically, having a function that should be called sort_array_and_print() suggests that you do not have the correct division of labour; the sort code should sort, and a separate function (like the dump_array() function I showed) should be used for printing an array.
As it turns out the reason why it was doing this is because when comparing an array's neighbor to itself as in:
if (values[i + 1] > values [i])
The fact that I was just checking that it is greater than, without checking if it is '=' then it was causing it to behave undesirably. So if the array is for example [1, 1, 5, 2, 6, 8] then by 1 being next to a 1, my program did not account for this behavior and acted the way it did.
I'm new to C and I'm having a small problem with my code:
int i, n;
int *arr;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
exit(1);
else {
arr = (int*) malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
} //end if
} //end while
What I'm trying to do is to make an array of n size and I want to stop reading when I get a '0' for example if I enter:
3
2
2
5
2
6
7
0
I want an array of size 3 with values 2, 2, 5, an array of 2 with values 6 and 7 and exit because of the 0
* Sorry, I left out an important part I think... In my code a call a calc() where I send arr, right after scanf("%d",&arr[i]) and then i'll return the value and then if the next values e.g. 2 isn't 0 I'll read, create a new array, send arr, print result on console and again if the next value is 0 then it will exit. *
Could you guys tell me where I'm wrong?
You are almost there!
You are creating the new arrays in arr, but this is a single pointer so can only refer to one block of memory. When you call malloc the new memory is stored in arr but the old memory is lost. You are 'leaking memory' because the machine has the old memory reserved but you don't have a variable storing it's address so you have no way to find it again.
If you only need to store the last list you should free the old memory (in arr) before malloc'ing the new space. If you need to store all the arrays you will need an array of pointers in arr.
edit:
You need to call free to 'free' the previously allocated memory before you allocate the new memory. At the first set of data you don't have any existing 'malloc' but it's always safe to free a NULL pointer, so simply set the pointer to NULL at the start.
Hint: It's always a good idea to set all the variables to some safe initial value when you define them.
int *arr=NULL; // Mark this as pointing to no memory
....
free(arr); // first time it does nothing, afterwards it deletes the previous reserved memory
arr = (int*) malloc(sizeof(int) * n); // as before this reserves some memory
The problems which are visible in your code are:
1. Checking uninitialized integer n in while. To fix this either initialize n to non zero or use a do{ ... } while() instead of while().
2. You need to validate the value of n which is read through scanf. malloc takes size_t type as the parameter which is unsigned int. But n being an integer can accept negative values, thus if a negative value is entered it will be passed as unsigned int to malloc, this may lead to undesired results (Also for loop will be executed incorrect number of times). You may also consider changing the type of n from integer to unsigned int type or change the exit condition to if( n < 1 ).
3. There is memory leak in your program. Memory allocated through malloc is not freed through free.
4. Do not assume that malloc will always succeed. Please check for the success of malloc through a NULL check i.e.
if (NULL == arr)
{
//error handling
}
5. exit with non zero value generally indicates abnormal termination. You can use break or return. break might be a better idea as it generally gets difficult to test a function as the exit points in the function increase (though this may not be true in your case, but it is FYI)
6. Optionally, you can check the return value of scanf to make sure that a valid input was entered.
Help this helps!
You're not initializing n so you may or may not enter your while loop. Starting n at -1 would be a reasonable thing to do:
int i, n = -1;
And you should cast the return value of malloc, that can hide problems.
You're also leaking memory because you're not calling free on that you get back from malloc and you're losing track of what you read in every time you assign a new value to arr. Brian Roach and Martin Becket have mentioned these things though.
Presumably you want to be able to access these arrays later.
As it is, you're losing your pointer to the previous array when you malloc the next one (and of course, causing a memory leak if it were a larger application).
You need to allocate a chuck of int * (a set of int pointers) then store each int pointer there.
The trick is ... if you don't know how many arrays you're going to need, you need your code to be dynamic (for example; allocate some amount of space, then allocate more if you run out).
Another option is that you could limit the number of series the user can input and tell them they're done when they reach it.
Here's some help if you wanted to go the latter route:
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5); /* max of 5 arrays */
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * n);
for(i = 0; i < n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
HOWEVER ... now you don't know how long each array is. Which is a problem. You'd need to keep track of that, or use a dynamic structure such as a linked list. In the example below, we add the length as the first element of each array:
int main()
{
int i;
int n = 1;
int **myArrayOfArrays = malloc(sizeof(int*) * 5);
int *arr;
int arrayCount = 0;
while(n != 0) {
scanf("%d", &n);
if(n == 0)
break;
else {
if (arrayCount == 4) {
printf("Woah there partner! That's enough!\n");
break;
}
else
{
arr = malloc(sizeof(int) * (n + 1)); /* one more than we need */
arr[0] = n; /* store the array length in the first element */
for(i = 1; i <= n; i++)
scanf("%d", &arr[i]);
myArrayOfArrays[arrayCount] = arr;
arrayCount++;
}
} //end if
} //end while
int j;
for (i = 0; i < arrayCount; i++)
{
int length = myArrayOfArrays[i][0]; /* retrieve the length */
for (j = 1; j <= length; j++)
printf("%d ", myArrayOfArrays[i][j]);
printf("\n");
}
}
Dynamic allocation using arrays / raw memory means you need to keep track of stuff. The better approach really is using a linked list for your data. In this case, you could have a linked list of nodes, each of which contained a link list of integers.