C program - weird Seg fault in dynamic programming algorithm - c

I'm writing a program in C to do a simple dynamic programming algorithm where you return the minimum number of coins needed to add up to a certain amount. Here's my code:
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
/*
This function returns the minimum number of stamps required for a given value.
It assumes that the given array contains the available stamp sizes, and that it
always contains 1, so a solution is always possible
*/
int min_number_of_stamps(const int* array, size_t array_size, int request) {
/* Construct a table with dimensions (array_size+1)*(request+1) */
int numRows = array_size + 1;
int numCols = request + 1;
int **DPtable;
DPtable = malloc(numRows*sizeof(int));
int i;
for (i = 0; i < numRows; i++) {
DPtable[i] = malloc(numCols*sizeof(int));
}
printf("%d",DPtable[4][0]);
int r, c, useIt, loseIt;
for (r = 0; r < numRows; r++) {
for (c = 0; c < numCols; c++) {
printf("%d,%d\n", r, c);
if (c==0) {
printf("1\n");
//if the amount of change is 0, 0 coins are needed
DPtable[r][c] = 0;
}
else if ((r==0) || c < array[r-1]) {
printf("2\n");
//if there are no coins or if the change needed is less than
//the smallest coin available, then 'infinity' coins are needed
DPtable[r][c] = INT_MAX;
}
else {
printf("3\n");
useIt = DPtable[r][c-array[r-1]] + 1;
loseIt = DPtable[r-1][c];
if (useIt <= loseIt) {
//if 'use it' requires fewer coins than 'lose it,' then
//'use it' coins are needed.
DPtable[r][c] = useIt;
}
else {
//if 'lose it' requires fewer coins, 'lose it' coins are needed
DPtable[r][c] = loseIt;
}
}
}
}
return DPtable[numRows][numCols];
}
int main() {
const int array[] = {1,5,10,25};
const int* stamps = &array[0];
printf("%d", min_number_of_stamps(stamps, 4, 44));
}
I'm getting a segfault when my inner for loop gets to the case where r=4 and c=0. I left my debugging print statements in because I'm lazy, but you can see where I got stuck. If I access the same place in the array outside of my for loops, there's no problem. But in the for loop, I get a `Segmentation fault: 11' message after it outputs "4,0" for the array element and "1" for the if case it's in. Can anyone see what I'm missing?

Learn to enable warnings & debugging for your compiler, i.e. gcc -g -Wall on Linux.
Learn to use a debugger, i.e. gdb -tui on Linux.
Consider using valgrind
EDIT
Many tutorials (in several languages, e.g. English, French, ....) for GCC, GDB, and ValGrind are easily found on the Web.

You're allocating dpTable incorrectly. It should be
DPtable = malloc(numRows*sizeof(int*));
See if that fixes the problem.

return DPtable[numRows][numCols];
thats out of bounds isn't it?

Related

Slow printf: why does __USE_MINGW_ANSI_STDIO=0 make it faster?

I wrote the code for a problem in codeforces and even though I believe I was doing it in the best time complexity it was exceeding the time limit on the 7th test case. After some testing, it seemed to me that the major amount of time was being taken by printf, which seemed odd since using printf some 3 * 10^5 times shouldn't be such a big deal. So I searched a lot and found this: https://codeforces.com/blog/entry/105687#comment-940911
Now I made the conclusion that using this line at the top of my code will make printf faster:
#define __USE_MINGW_ANSI_STDIO 0
So I ran my code with the above included and voila what was exceeding the time limit of 1s earlier now with the inclusion of just one line of code got accepted in merely 62 ms.
I didn't understand most of the other stuff that was talked about in the link like MinGW implementations and all.
So my question is, firstly why does it work this way? Secondly, can I/should I keep using the above line of code in all my programs on codeforces from now on?
P.S. I also found this blog: https://codeforces.com/blog/entry/47180
It was too confusing for me to grasp for the time being but maybe someone else can understand it and shed some light on the matter.
Also, here is the codeforces problem: https://codeforces.com/contest/1774/problem/C
Here is my solution:
https://codeforces.com/contest/1774/submission/185781891
I don't know the entire input as codeforces doesn't share it and it'd be very very big. But I know that the value inputted to the tests variable is 3, the values inputted to n[0], n[1], n[2] are 100000, 100000, 100000
Here is my code:
#define __USE_MINGW_ANSI_STDIO 0
#include <stdio.h>
#include <stdlib.h>
// #include <math.h>
// #include <string.h>
// #define lint long long int
// Function Declarations
int main(void)
{
int tests;
scanf("%i", &tests);
int **answers = malloc(tests * sizeof(int*));
int *n = malloc(sizeof(int) * tests);
for (int i = 0; i < tests; i++)
{
scanf("%i", &n[i]);
char *enviro = malloc((n[i]) * sizeof(int));
answers[i] = malloc((n[i] - 1) * sizeof(int));
int consec = 1; // No. of same consecutive elements at the very
// end.
scanf("%s", enviro);
answers[i][0] = 1; // Case where x = 2;
for (int x = 3; x < n[i] + 1; x++)
{
// comparing corresponding to current x vs previous x
if (enviro[x - 2] == enviro[x - 3])
{
consec++;
}
else
{
consec = 1;
}
answers[i][x - 2] = x - consec;
}
// Free loop variables
free(enviro);
}
/* if (tests == 3)
{
printf("n[%i] = %i\n", i, n[i]);
} */
for (int i = 0; i < tests; i++)
{
for (int j = 0; j < n[i] - 1; j++)
{
printf("%i ", answers[i][j]);
}
printf("\n");
free(answers[i]);
}
// Free variables
free(answers);
return 0;
}
EDIT: So I tried the following code for the same problem on codeforces (https://codeforces.com/contest/1774/submission/185788962) just to see the execution time:
// #define __USE_MINGW_ANSI_STDIO 0
#include <stdio.h>
#include <math.h>
int main(void)
{
int n = pow(10, 5);
for (int i = 0; i < n; i++)
{
printf("*");
}
}
Without the #define __USE_MINGW_ANSI_STDIO 0 it gave an e.t. of 374ms. With it, it gave e.t. of 15ms.
It seems like MinGW defined their own printf() functions, __mingw_printf(). This is done to fix format specifiers' problems on some old Windows operating systems, as seen in their wikis. The macro __USE_MINGW_ANSI_STDIO is set to 0 if you don't want to use MinGW's implementation, and 1 if you do.
It also seems like MinGW's implementation is slower, so not using it will make your code faster.

Finding sum of square of two numbers in an array

My program should take a number from the user, and find the two numbers in an array such that the sum of their squares equals the user input squared. However, I'm having trouble doing this, as well as understanding all the errors I'm getting.
Here's my current attempt:
#include <stdio.h>
int numberaa;
scanf("%d",&numberaa);
int main()
{
int i,j;
int array[9] = {2,-4,6,3,9,0,-1,-9};
for (i = 0; i <= 8; i++)
for (j = 0; j <= 8; J++0)
firstone==i*i
secondone==j*j
if {
firstone+secondone=numberaa;
printf("The Numbers are %d and %d",j,i,numberaa);
return 0
};
Change
firstone+secondone=numberaa;
to
numberaa = firstone + secondone;
Ah! You need to grab a basic C book. For this time I am posting a correct code for you. Hope you will learn something.
#include <stdio.h>
int main()
{
int i,j;
int array[9] = {2,-4,6,3,9,0,-1,-9};
int numberaa;
scanf("%d",&numberaa);
for (i = 0; i <= 8; i++){
for (j = 0; j <= 8; J++0){
firstone = i*i
secondone = j*j
if(numberaa == firstone + secondone)
printf("The Numbers are %d and %d",j,i,numberaa);
}
}
return 0
}
You need to read through at least the introductory chapter of a book on C and work through the examples. That means typing them out (no, don't copy and paste), compiling them, and running them to understand what makes them work and what breaks them.
When you write your own code, always compile with warnings enabled, e.g. gcc -Wall -o my_executable_name my_code.c, and pay attention to the line numbers referenced in compiler errors and warnings.
I'll point out some locations of errors in your code below:
#include <stdio.h>
int numberaa; // Currently you're declaring this as a global. NO! not what you want.
scanf("%d",&numberaa); // This isn't going to happen out here. NO! NO NO NO!
int main() // Specify your parameters. int main(void)
{
int i,j;
int array[9] = {2,-4,6,3,9,0,-1,-9}; // why specify an array of 9 but store just 8 elements??
for (i = 0; i <= 8; i++) // These are the correct limits for array[9].
for (j = 0; j <= 8; J++0) // j and J are not the same. What is J++0 ????!! Also, read about "blocks" and try a for-loop example with more than one line.
firstone==i*i // WTF?? Have you even tried to compile this?
secondone==j*j // See line above.
if { // Likewise
firstone+secondone=numberaa; // Likewise again.
printf("The Numbers are %d and %d",j,i,numberaa); // How many formatting flags does your first argument have, and how many are to be inserted?
return 0 }; // again, have you tried to compile this?
Short version:
Semicolons
Assignment vs. equality
Scope of variables
Blocks, brace usage
syntax of if statements
You also aren't squaring the user input.
Efficiency: you only need to calculate firstone = i * i once for each i value, so take it outside the j loop.

Trying to write a function to shuffle a deck in C

So all I'm trying to do is take an input from the user of how many cards to use and then randomly assign each card to a different index in an array. I'm having extensive issues getting the rand function to work properly. I've done enough reading to find multiple different ways of shuffling elements in an array to find this one to be the easiest in regards to avoiding duplicates. I'm using GCC and after I input the amount of cards I never get the values from the array back and if I do they're all obscenely large numbers. Any help would be appreciated.
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
void main(){
srand(time(NULL));
int d, c, i, z, l, r;
printf("Enter the deck length: ");
scanf("%d\n ", &c);
int deck[c];
int swap[c];
z = c;
for(l=0; l<c; l++){
swap[l] = l;
}
for(i=z; i=0; i--){
r = rand() / i
deck[i] = swap[r];
for(r; r=(c-1); r++){
swap[r] = swap[(r+1)];
}
}
for(d = 0; d < c; d++){
printf("%d ", deck[d]);
}
return;
}
I can spot one major problem here:
for(i=z; i=0; i--)
^^^
This loop will never execute since you are using assignment(=) and setting i to 0 therefore the condition will always be false, although using equality(==) will still be false in this case, you probably want:
for(i=z; i!=0; i--)
This means you will be using deck unitialized which is undefined behavior. Once you fix that you have a similar problems here:
for(r; r=(c-1); r++){
main has to return int and your return at the end needs to provide a value.
Turning on warning should have allowed you to find most of these issues, for example using -Wall with gcc gives me the following warning for both for loops:
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
Note, see How can I get random integers in a certain range? for guidelines on how to use rand properly.
You basically need to be able to generate 52 numbers pseudo-randomly, without repeating. Here is a way to do that...
First, loop a random number generator 52 times, with a method to ensure none of the random numbers repeat. Two functions in addition to the main() will help to do this:
#include <ansi_c.h>
int NotUsedRecently (int number);
int randomGenerator(int min, int max);
int main(void)
{
int i;
for(i=0;i<52;i++)
{
printf("Card %d :%d\n",i+1, randomGenerator(1, 52));
}
getchar();
return 0;
}
int randomGenerator(int min, int max)
{
int random=0, trying=0;
trying = 1;
while(trying)
{
srand(clock());
random = (rand()/32767.0)*(max+1);
((random >= min)&&(NotUsedRecently(random))) ? (trying = 0) : (trying = 1);
}
return random;
}
int NotUsedRecently (int number)
{
static int recent[1000];//make sure this index is at least > the number of values in array you are trying to fill
int i,j;
int notUsed = 1;
for(i=0;i<(sizeof(recent)/sizeof(recent[0]));i++) (number != recent[i]) ? (notUsed==notUsed) : (notUsed=0, i=(sizeof(recent)/sizeof(recent[0])));
if(notUsed)
{
for(j=(sizeof(recent)/sizeof(recent[0]));j>1;j--)
{
recent[j-1] = recent[j-2];
}
recent[j-1] = number;
}
return notUsed;
}

Why is this C program crashing?

I have a simple test program in C to scramble an array of values on the heap. Sidenote: I know the random logic here has a flaw that will not allow the "displaced" value to exceed RAND_MAX, but that is not the point of this post.
The point is that when I run the code with N = 10000, every once in a while it will crash with very little information (screenshots posted below). I'm using MinGW compiler. I can't seem to reproduce the crash for lower or higher N values (1000 or 100000 for example).
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
const int N = 10000;
int main() {
int i, rand1, rand2, temp, *values;
/* allocate values on heap and initialize */
values = malloc(N * sizeof(int));
for (i = 0; i < N; i++) {
values[i] = i + 1;
}
/* scramble */
srand(time(NULL));
for (i = 0; i < N/10; i++) {
rand1 = (int)(N*((double)rand()/(double)RAND_MAX));
rand2 = (int)(N*((double)rand()/(double)RAND_MAX));
temp = values[rand1];
values[rand1] = values[rand2];
values[rand2] = temp;
}
int displaced = 0;
for (i = 0; i < N; i++) {
if (values[i] != (i+1)) {
displaced++;
}
}
printf("%d numbers out of order\n", displaced);
free(values);
return 0;
}
it may be because rand() generates a random number from 0 to RAND_MAX inclusive so (int)(N*((double)rand()/(double)RAND_MAX)) can be N, which exceeds the array boundary. however, i don't see why that would vary with array size (it does explain why it only crashes sometimes, though).
try /(1+(double)RAND_MAX) (note that addition is to the double, to avoid overflow, depending on the value of RAND_MAX) (although i'm not convinced that will always work, depending on the types involved. it would be safer to test for N and try again).
also, learn to use a tool from Is there a good Valgrind substitute for Windows? - they make this kind of thing easy to fix (they tell you exactly what went wrong when you run your program).

C programming - A array and a random number combined question?

this is the part of my code I'm having trouble with. I can't understand why its doing it wrong. I have an array where it stores numbers 0 - 25 which are cases. The numbers are to be randomized and overwritten into the array. Only condition is is that no number can be doulbes, there can only be one of that number. I'm not asking you to do my code but do hint me or point me in the write directions. I am trying to learn :)
The problem lies within the second do loop. I can get the numbers to be randomized, but I get doubles. I have created a loop to check and fix this, but it's not working. The code does run, and doubles do still happen and I can't see why. It looks correct to me. Please look, thank you (:
This is what I have done originally (at the very end is where I am at now):
int check_double = 0;
int i = 0;
int counter = 0;
int array_adder = 0;
int random_number = 0;
int cases[] = {
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
};
float money[] = {
0.01,1,5,10,25,50,75,100,200,300,400,500,750,1000,5000,10000,25000,50000,750000,100000,200000,300000,400000,500000,750000,1000000
};
//Randomize all case number and realine them in the array
srand ( time(NULL) );
do
{
cases[counter]= rand() % 26;
counter += 1;
printf("%d\n", cases[counter]);
}
while (counter <= 25);
//make sure there are no doubles in the array, just 0 - 25 and not a single number repeated twice
do
{
check_double = 0;
for (i = 0; i < counter; i++)
{
if (cases[counter] == cases[i])
{
cases[counter] = rand()% 26;
check_double == 1;
}
}
}
while (check_double != 0);
Currently, what I had achived after that was combing both loops and check for doubles as the array goes. This is what I made, it still has doubles and im not sure why, I only posted the cose with both loops combined:
do
{
cases[counter]= rand() % 26;
if (cases[counter]>=1);
for(i=0;i<=counter;i++)
if (cases[counter]==cases[i])
{
cases[counter]=rand()% 26;
}
printf("%d\n",cases[counter]);
counter+=1;
}
Robsta, you could try the following piece of code, I have run this in Dev-C++, any changes that you require can be made from your side. But, I assure you that this code generates what you intend.
int check_double = 0;
int i = 0;
int counter = 0;
int cases[] = {
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
};
//Randomize all case number and realine them in the array
srand ( time(NULL) );
do
{
cases[counter]= rand() % 26;
for(i=0;i<counter;i++)
if (cases[counter]==cases[i]){
while (cases[counter]==cases[i])
{
cases[counter]=rand()% 26;
}
i=0;
}
printf("%d\t%d\n",counter,cases[counter]);
counter+=1;
}while (counter <= 25);
If you have any clarifications required, I would love to discuss with you.
-Sandip
You're only ever writing over the last value in the array:
for(i=0;i<counter;i++)
if (cases[counter]==cases[i])
You need to loop through as you are, then have an inner loop, where you compare all the other entries to the current one.
Even easier would be to do the loop where you set each random number, so when you set cases[3] for example, loop from 0 to 2 and check to see if your new value for 3 clashes, if so, wash - rinse - repeat!
You have this line of code:
check_double==1;
That doesn't change check_double because it's ==, not =. == compares; it doesn't assign. Change that line to this:
check_double=1;
A helpful compiler (clang in this example) will give you a warning about this:
test.c:5:14: warning: expression result unused [-Wunused-value]
check_double==1;
~~~~~~~~~~~~^ ~
You can't check for duplicates with a single loop. You need to at least compare every possible pair of elements to be able to see if there's a duplicate. I'm guessing you forgot to loop over counter somewhere inside the second do...while?
Note that your method is not guaranteed to terminate. (Very, very likely but not certain.) Why don't you simply shuffle the cases array? Shuffling is simple but tricky; see Fisher-Yates (or Knuth) Shuffle for a simple algorithm.
If you are asking how to randomly sequence the number 1-25 then you could do something like this. This is a very brute-force way of generating the sequence, but it does work and might give you a starting point for something more optimized.
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <conio.h>
const int LastNumber = 25;
bool HasEmpty(int available[LastNumber][2])
{
bool result = false;
for(int i = 0; i < LastNumber; i++)
{
if (available[i][1] == 0)
{
result = true;
break;
}
}
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int available[LastNumber][2];
int newSequence[LastNumber];
srand((unsigned int)time(NULL));
for(int i = 0; i < LastNumber; i++)
{
available[i][0]=i;
available[i][1]=0;
}
int usedIndex = 0;
while (HasEmpty(available))
{
int temp = rand() % (LastNumber + 1);
if (available[temp][1] == 0)
{
newSequence[usedIndex++] = available[temp][0];
available[temp][1] = 1;
}
}
for(int i = 0; i < LastNumber; i++)
{
printf("%d\n",newSequence[i]);
}
getch();
return 0;
}

Resources