Changing the value of elements in an array in C - c

My program crashes once it reaches this function in my code. I printed the arrays in the function that are going in and commented out everything else and
they are getting passed correctly. I can't figure out why it crashes here.
The arrays are numbers in ascending order.
Maybe my loops or if statements are not right? I think maybe I'm not correctly changing the value in the array at index "d" when it reaches attackerArmy[d] = '0'; //represent 0 as defeated ?
long int defeatedArmies(long int* attackerArmy, long int* defenderArmy, long int size){
long int i,j,defeated = 0,d;
for(i=0;i<size;i++){
for(j=0;j<size;j++){
//loop for the highest attack value that is lower than defender
if(attackerArmy[j] < defenderArmy[i])
d = j; // save the index where it is highest
if(attackerArmy[j] > defenderArmy[i])
//no point in checking unnecessary values
break;
}
attackerArmy[d] = '0'; //represent 0 as defeated
}
for(i=0;i<size;i++){
if(attackerArmy[i] == 0) //count how many defeated armies happened
defeated++;
}
return defeated;
}

Problem
if attackerArmy[j] >= defenderArmy[i] is true, d remains uninitialized causing the undefined behavior when you access its value in attackerArmy[d] = '0';.
Possible fix
Initialize d when you declare it.
ex:
long int d = -1L;
...
if(d != -1L) attackerArmy[d] = '0';

Related

I'm having a hard time using pass by reference

I don't know why I keep on getting errors in my code when I'm trying to do pass-by-reference, for finding the largest number of an integer using recursion.
My code works when it's pass-by-value, but I fail to do it correctly in pass-by-reference.
My main:
#include <stdio.h>
#include <math.h>
void largest_digit(int* digit);
int main() {
int num;
printf("\nPlease enter a number ");
scanf("%d", &num);
largest_digit(&num);
printf("The largest digit = %d\n", num);
return 0;
}
My function:
void largest_digit(int* digit) {
int hold, hold1;
if(*digit == 0 || *digit < 0) {
*digit = 0;
*digit;
return;
}
// If-statement with Recursion.
if(*digit > 0){
hold = *digit % 10;
hold1 = largest_digit(*digit/10);
if(hold > hold1) {
hold = *digit;
*digit;
return;
} else {
hold1 = *digit;
*digit;
return;
}
}
}
As someone said before, the largest_digit function is void, so it can't be assinged to a variable when is called. What you can do instead, is modifying *digit before the call, and then assign the value of *digit to what you want, in this case hold1.
Other thing is that you need to save the value into *digit before returning, for example, instead of doing hold = *digit, you should do *digit = hold.
Here are the suggested modifications:
void largest_digit(int* digit) {
int hold, hold1;
if(*digit == 0 || *digit < 0) {
*digit = 0;
return;
}
// If-statement with Recursion.
if(*digit > 0){
hold = (*digit) % 10;
(*digit) /= 10;
largest_digit(digit);
hold1 = *digit;
if(hold > hold1) {
*digit = hold;
return;
} else {
*digit = hold1;
return;
}
}
}
With this main,
int main() {
int a=123, b=652, c=3274;
largest_digit(&a);
largest_digit(&b);
largest_digit(&c);
printf("%d\n",a);
printf("%d\n",b);
printf("%d\n",c);
return 0;
}
the output is
3
6
7
You said you were passing it by reference, but you just tried to pass it by value here
hold1 = largest_digit(*digit/10);
Create a new int with *digit/10 and pass the address to largest_digit
int hold1Temp = *digit/10;
hold1 = largest_digit(&hold1Temp);
EDIT: Your function should be something like this:
void largest_digit (int* digit)
{
if (*digit <= 0) return; // if there's no more digit to compare, stop
int currentDigit = *digit % 10; // if you receive 982, it gets the 2
int nextDigit = *digit/10; // if you receive 982, it turns into 98
largest_digit(&nextDigit); // does the same thing again
*digit = currentDigit > nextDigit ? currentDigit : nextDigit; // chooses the biggest digit
}
A couple of things first:
The unary indirection operator (*) used on a pointer means "look at what is this pointing to". Therefore, the statement *digit; alone is not useful to anything. You can very well remove it from your code (I see you use it multiple times), perhaps you meant to do an assignment? The statement *digit = X; is an assignment and modifies the data pointed by the pointer.
"Passing by reference" does not exist in C. You can only pass by value. That value though can be a pointer to another value, that is how you "simulate" passing something by reference.
A function declared as void f(...) does not return any value. Therefore, assigning the "return value" of such a function to a variable does not make sense.
Now, considered the above:
Your call largest_digit(*digit/10) is not passing a pointer, but dereferencing the pointer digit, dividing the value by 10, and then passing that as parameter. As you already figured, this is wrong. To correctly pass by reference in your case, you would need to either modify the original value pointed to by digit, or create a new one and pass its address.
In any case, passing a pointer around (instead of the value directly) for this kind of recursive function does not make much sense and is only a complicated twist that does not accomplish much other than making your life harder. Use a plain value as argument.
int largest_digit(int num) {
if (num < 0)
return largest_digit(-num);
if (num == 0)
return 0;
int cur = num % 10;
int next = largest_digit(num / 10);
if (cur > next)
return cur;
return next;
}
int main(void) {
printf("%d\n", largest_digit(1923)); // 9
printf("%d\n", largest_digit(4478)); // 8
printf("%d\n", largest_digit(-123)); // 3
}
NOTE: for simplicity, the above function also handles negative numbers by calling largest_digit(-num) if the number is negative, therefore it only supports negative digits down to INT_MIN+1 (that is, it does not correctly handle INT_MIN).
Your trouble is that other than the case where *digit is negative, you never actually set *digit. Each time you do this:
*digit;
The above only dereferences the pointer and looks up the value, but it doesn't actually change it. What you need to do on each of your return routes is to actually set the value to something:
*digit = ...something...;
Without setting this value anywhere, the value of num in your main() function is never actually going to change.
In addition, you are treating largest_digit as if it has a return value, which it does not:
hold1 = largest_digit(*digit/10); // <- assigning the return value does not make sense

While loops and arrays causing very odd behaviour...maybe a memory mixup

I'm tired of this tom-foolery occurring during runtime , although I'm sure we all are, when our programs screw up at runtime in the most obscure ways.
Getting to the point, the entire source code is a bit large to place here, but still <200 lines, so that's here . Use it if running the program, since the code I will post below is just functions, where I think the error lies.
Context : This is a sort of shift cipher with 8 different shifts taken using an 8 digit pin.
The issue is strange. Basically, the encrypt() function works correctly always -I've matched it by doing the algorithm for myself on paper ; for example, ABC is correctly encoded to 3c 45 46 -6f when the Pin is 12345678.
The strange issues are with the decrypt() function.
When the program is run for the first time, trying to run decrypt() on a valid ciphertext-pin pair always returns nothing except a /n (newline) . When tried with a different valid pin-ciphertext pair, after a successful run of encrypt() is done first, the decrypt() function just returns either the same message which was just encrypted or some other random output from the previously encoded message.
Without further ado, the legendarily screwed up decrypt function which I have rebuilt thrice now -
void decrypt()
{
printf("\n");
int *digits = pin(); int d[8];
getchar();
for (int i=0;i<8;i++)
d[i] = *(digits + i); //puts each digit in a local array.
printf("\nEnter encoded message -\n\n");
getchar();
int j; char ch, msg[3002];
for(int i=0; i < 3000;i++)
{
scanf("%x",&j);
if(j==-111){
msg[i] = '\0'; //terminates string with \0
break;
}
else{
if(ctln(i)==1)
ch = j - d[2];
else if(fib(i)==1)
ch = j + d[4];
else if(luc(i)==1)
ch = j - d[0];
else if(pent(i)==1)
ch = j + d[6];
else if(hex(i)==1)
ch = j - d[3];
else if(prm(i)==1)
ch = j + d[7];
else {
if(i%2 == 0)
ch = j - d[1];
else
ch = j + d[5];
msg[i] = ch;
}
}
}
printf("\nDecrypted message -\n\n");
puts(msg);
}
For context, as well as finding the culprits here, do make sure to read the full code here , with the pin() returning a pointer to a static int array holding all 8 digits , as well as the ctln() , fib(), luc(), pent(), hex(), prm() [ which check if position value i of char in message is a part of Catalan, Fibonacci , Lucas, Pentagon, Hexagon, Prime number series. More here.
Edit 1
I have already tried keeping different variable names, and some other things I can't fully recall. Also, because it is very relevant, below is the pin() function:
int *pin()
{
int num,q=0; static int pins[8];
printf("Enter 8-digit PIN : ");
scanf("%d", &num);
for(register int i = 10000000 ; i >= 1 ; i = (i/10)) // i is position of digit.
{
int d = ((num - (num % i)) / i); // d stores 'digit' ( divides quotient of (num % i) by i)
pins[q] = d; q++;
num = (num - ( d * i ));
}
return pins ; // pointer to static array storing digits of PIN
}
Edit 2
I had wrongly assigned pins[6] rather than pins[8] in the original code, I have corrected it but am still facing the same errors.
Edit 3
After correcting the mistake pointed out by MikeCAT, it now ignores the first character when deciphering.
Edit 4
The getchar() before scanf() was to blame, removing it fixes the last issue too. Thanks #MikeCAT !
In your decrypt() function, msg[i] = ch; is executed only if none of the functions ctln, fib, luc, pent, hex, prm returned 1.
Therefore, uninitialized value of non-static local variable msg, which is indeterminate, may be used for printing and undefined behavior may be invoked.
The part
msg[i] = ch;
}
should be
}
msg[i] = ch;
as it is done in encrypt() function.

C: realloc works on Linux, but not on Windows

this is my first question on Stack Overflow, sorry if it's not well written.
I have a little problem. I wrote a program in C (I'm currently learning C, I am a newbie, my first language, don't say I should've learnt Python, please, because I'm doing just fine with C). So, I wrote this little program. It's an attempt of mine to implement a sorting algorithm (I made the algorithm myself, with no help or documentation, it's very inefficient I think, I was just fooling around, though I don't know whether the algorithm already exists or not). The only sorting algorithm I know is QuickSort.
In any case, here is the final program (has plenty of comments, to help me remember how it works if I'll ever revisit it):
// trying to implement my own sorting algorithm
// it works the following way:
// for an array of n integers, find the largest number,
// take it out of the array by deleting it, store it
// at the very end of the sorted array.
// Repeat until the original array is empty.
// If you need the original array, simply
// make a copy of it before sorting
/***************************************/
// second implementation
// same sorting algorithm
// main difference: the program automatically
// computes the number of numbers the user enters
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int *sort(int *a, int n); // sort: the actual sorting function
char *read_line(char *str,int *num_of_chars); // read_line: reads input in string form
int *create_array(char *str, int n); // create_array: counts the num of integers entered and extracts them
// from the string the read_line function returns, forming an array
int size_of_array_to_be_sorted = 0; // of integers
int main(void)
{
int *array, i, *sorted_array, size = 3;
char *str = malloc(size + 1);
if (str == NULL)
{
printf("\nERROR: malloc failed for str.\nTerminating.\n");
exit(EXIT_FAILURE);
}
printf("Enter the numbers to be sorted: ");
str = read_line(str, &size);
array = create_array(str, size + 1);
sorted_array = sort(array, size_of_array_to_be_sorted);
printf("Sorted: ");
for (i = 0; i < size_of_array_to_be_sorted; i++)
printf("%d ", sorted_array[i]);
printf("\n\n");
return 0;
}
int *sort(int *a, int n)
{
int i, j, *p, *sorted_array, current_max;
sorted_array = malloc(n * (sizeof(int)));
if (sorted_array == NULL)
{
printf("ERROR: malloc failed in sort function.\nTerminating.\n");
exit(EXIT_FAILURE);
}
for (i = n - 1; i >= 0; i--) // repeat algorithm n times
{
current_max = a[0]; // intiliaze current_max with the first number in the array
p = a;
for (j = 0; j < n; j++) // find the largest integer int the array
if (current_max < a[j])
{
current_max = a[j];
p = (a + j); // make p point to the largest value found
}
*p = INT_MIN; // delete the largest value from the array
sorted_array[i] = current_max; // store the largest value at the end of the sorted_array
}
return sorted_array;
}
char *read_line(char *str, int *num_of_chars)
{
int i = 0; // num of chars initially
char ch, *str1 = str;
while ((ch = getchar()) != '\n')
{
str1[i++] = ch;
if (i == *num_of_chars) // gives str the possibility to
{ // dinamically increase size if needed
str1 = realloc(str, (*num_of_chars)++);
if (str1 == NULL)
{
printf("\nERROR: realloc failed in read_line.\nTerminating.\n");
exit(EXIT_FAILURE);
}
}
}
// at the end of the loop, str1 will contain the whole line
// of input, except for the new-line char. '\n' will be stored in ch
str1[i++] = ch;
str1[i] = '\0'; // store the null char at the end of the string
return str1;
}
int *create_array(char *str, int n)
{
int *array, i, j, k, num_of_ints = 0;
for (i = 0; i < n; i++) // computing number of numbers entered
if (str[i] == ' ' || str[i] == '\n')
num_of_ints++;
array = calloc((size_t) num_of_ints, sizeof(int)); // allocacting necessary space for the array
if (array == NULL)
{
printf("\nERROR: calloc failed in create_array.\nTerminating.\n");
exit(EXIT_FAILURE);
}
k = 0;
i = 1; // populating the array
for (j = n - 1; j >= 0; j--)
{
switch (str[j])
{
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': array[k] += ((str[j] - '0') * i);
i *= 10;
break;
case '-': array[k] = -array[k]; // added to support negative integers
default: i = 1;
if (str[j] == ' ' && (str[j - 1] >= '0' && str[j - 1] <= '9'))
/* only increment k
*right before a new integer
*/
k++;
break;
}
}
// the loop works in this way:
// it reads the str string from the end
// if it finds a digit, it will try to extract it from the
// string and store in array, by adding to one of the elements
// of array the current char - ASCII for '0', so that it actually gets a digit,
// times the position of that digit in the number,
// constructing the number in base 10: units have 1, decimals 10, hundreds 100, and so on
// when it finds a char that's not a digit, it must be a space, so it resets i
// and increments k, to construct a new number in the next element of array
size_of_array_to_be_sorted = num_of_ints;
return array;
}
I've written everything myself, so if you think I use some bad methods or naive approaches or something, please tell me, in order for me to be able to correct them. Anyways, my problem is that I have these 'try to handle errors' if statements, after every call of malloc, calloc or realloc. I have a Linux machine and a Windows one. I wrote the program on the Linux one, which has 4GB of RAM. I wrote it, compiled with gcc, had to change a few things in order to make it work, and it runs flawlessly. I have no problem. I then copied it onto a USB drive and compiled it with mingw on my Windows machine, which has 8GB of RAM. I run it, and if I give it more than 3 2-digit integers, it displays
ERROR: realloc failed in read_line.
Terminating.
At least I know that the 'error handling' if statements work, but why does this happen? It's the same code, the machine has twice as much RAM, with most of it free, and it runs with no problem on Linux.
Does this mean that my code is not portable?
Is it something I don't do right?
Is the algorithm wrong?
Is the program very, very inefficient?
Sorry for the long question.
Thanks if you wanna answer it.
The line in question is:
str1 = realloc(str, (*num_of_chars)++);
where *num_of_chars is the current size of str. Because you are using post-increment, the value passed for the new allocation is the same as the current one, so you haven't made str any bigger, but go ahead and act as if you had.

how to initialize array of unknown size in c

I am doing a homework assignment for an intro to programming class in c.
I need to write a program that looks at an int array of unknown size (we are given a initializer list as the test case to use), and determine all the duplicates in the array.
To make sure that an element that was already found to be a duplicate doesn't get tested, I want to use a parallel array to the original that would hold the numbers of all the elements that were duplicates.
I need this array to be the same size as the original array, which of course we don't really know till the initializer list is given to us.
I tried using sizeof() to achieve this, but visual studio says that is an error due to the variable size (const int size = sizeof(array1);) not being constant. Am I not using sizeof correctly? Or is this logic flawed?
Perhaps there is another way to approach this, but I have yet to come up with one.
Here is the code included below, hope the comments don't make it too hard to read.
// Dean Davis
// Cs 1325
// Dr. Paulk
// Duplicates hw
#include <stdio.h>
int main()
{
int array1[] = { 0,0,0,0,123,124,125,3000,3000,82,876,986,345,1990,2367,98,2,444,993,635,283,544, 923,18,543,777,234,549,864,39,97,986,986,1,2999,473,776,9,23,397,15,822,1927,1438,1937,1956,7, 29,- 1 };
const int size = sizeof(array1);
int holdelements[size];
int a = 0; // counter for the loop to initialize the hold elements array
int b = 0; // counter used to move through array1 and be the element number of the element being tested
int c = 0; // counter used to move through holdelements and check to see if the element b has already been tested or found as duplicates
int d = 0; // counter used to move through array1 and check to see if there are any duplicates
int e = 0; // counter used to hold place in hold element at the next element where a new element number would go. sorry if that makes no sense
int flag = 0; // used as a boolian to make sure then large while loop ends when we reach a negative one value.
int flag2 = 0; // used as a boolian to stop the second while loop from being infinite. stops the loop when the end of hold elements has been reached
int flag3 = 0; // used to close the third while loop; is a boolian
int numberofduplicates=0;// keeps track of the number of duplicates found
for (a; a < size; a++)
{
if (a == (size - 1))
holdelements[a] = -1;
else
holdelements[a] = -2;
}
while (!flag)
{
flag2 = 0;
flag3 = 0;
if (array1[b] == -1)
flag = 1;
else
{
while ((!flag) && (!flag2))
{
if (holdelements[c] == -1)
flag2 = 1;
else if (array1[b] == holdelements[c])
{
b++;
c = 0;
if (array1[b] == -1)
flag = 1;
}
}
while (!flag3)
{
if (array1[d] == -1)
flag3 = 1;
else if (array1[b] == array1[d] && b != d)
{
printf("Duplicate of %d, index %d, was found at index %d.\n", array1[b], b, d);
holdelements[e] = d;
d++;
e++;
numberofduplicates++;
}
}
}
b++;
}
printf("Total Duplicates Found: %d\n", numberofduplicates);
return 0;
}
redo to the following:
const int size = sizeof(array1)/sizeof(int);

Segmentation fault (core dumped) error, in a C search function

I'm trying to write a C program to take an array of discrete positive integers and find the length of the longest increasing subsequence.
'int* a' is the array of randomly generated integers, which is of length 'int b'
call:
lis_n = answer(seq, seq_size);
function:
int answer(int* a, int b) {
if (a == NULL) {return -1;}
int i = 0;
int j = 0;
int k = 0;
//instantiate max and set it to 0
int max = 0;
//make an array storing all included numbers
int included[b];
memset(included, 0, b*sizeof(int));
//create a pointer to the index in included[] with the largest value
int indexMax = 0;
//create a pointer to the index in a[]
int indexArray = 0;
//index of a[] for max included
int maxToA = 0;
//set the first included number to the first element in a[]
included[indexMax] = a[indexArray];
//loop until break
while (1) {
if (a[indexArray] > included[indexMax]/*digit greater than last included*/) {
//include the digit
included[indexMax+1] = a[indexArray];
//increment current max pointer
indexMax++;
}
j = b - 1;
while (indexArray >= j/*pointer is at end"*/) {
if (j == (b - 1)) {
if ((indexMax+1) > max/*total is greater than current max*/) {
max = indexMax + 1;
}
}
if (a[b-1] == included[0]/*last element is in included[0], stop*/) {
return max;
} else {
//max included is set to zero
included[indexMax] = 0;
//max included pointer decreased
indexMax--;
//set array pointer to new max included
for (k=0;k<(b-1);k++) {
if (a[k] == included[indexMax]) {
indexArray = k;
}
}
//increment array pointer
indexArray++;
j--;
}
}
indexArray++;
printf("(");
for (i=0;i<b;i++) {
printf("%d,",included[i]);
}
printf(")");
}
}
I'm receiving 'Segmentation fault (core dumped)' in the terminal upon running.
Any help would be awesome.
You have declared
int indexMax = 0;
And here you use it as an array index
incuded[indexMax] = 0;
You increment and decrement it
indexMax++;
...
indexMax--;
You check its range but you don't limit it, you alter the value you compare it with
if ((indexMax+1) > max/*total is greater than current max*/) {
max = indexMax + 1;
}
You never check indexMax against b or with 0
int included[b];
So you are almost guaranteed to exceed the bounds of included[].
Some general points of advice. Make your function and variable names meaningful. Avoid making a premature exit from a function wherever possible. Avoid while(1) wherever possible. And never make assumptions about array sizes (including C "strings"). It might seem hard work putting in the overhead, but there is a payoff. The payoff is not just about catching unexpected errors, it makes you think about the code you are writing as you do it.
I've done something like this for homework before. I got help from:
https://codereview.stackexchange.com/questions/30491/maximum-subarray-problem-iterative-on-algorithm
Make sure you are not trying to index past the size of your array. What I would do would be to find out the size of array a[] (which looks like it is b) and subtract 1. Make sure you are not trying to access past the size of the array.

Resources