I'm building a program that simulates the tortoise and the hare race. The way I'm doing it is I create a SIZE 70 array of '_' to simulate the racetrack. Then I create 2 pointers, char *harePtr and char *tortoisePtr, that point to elements in that array (each one starting at [0]) The elements in the array that the pointers point to I'm also trying to change to 'T' and 'H' to simulate their locations on the track.
From there I've algorithms developed to determine, based on a random number generator, the action each would take.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 70
enum winner {TORTOISE, HARE};
int raceRunner (char wRaceTrack[], void (*moveHare)(char *harePtr, int i), void (*moveTortoise)(char *tortoisePtr, int i));
void moveHare (char *harePtr, int i);
void moveTortoise ( char *tortoisePtr, int i);
int main() {
char racetrack [SIZE];
size_t i;
for (i = 0; i < SIZE; i++)
racetrack[i] = '_';
int winner;
winner = raceRunner(racetrack, moveHare, moveTortoise);
if (winner == 1)
printf("The hare won!");
if (winner == 2)
printf("The tortoise won!");
}
int raceRunner (char wRaceTrack[], void (*moveHare)(char *harePtr, int i), void (*moveTortoise)(char *tortoisePtr, int i)){
srand(time(NULL));
int move = 1 + rand() %10;
char *harePtr = wRaceTrack;
char *tortoisePtr = wRaceTrack;
size_t i;
for (i = 0; i < SIZE; i++)
printf("%c,", wRaceTrack[i]);
printf("\n\n");
moveHare(harePtr, move);
moveTortoise(tortoisePtr, move);
i = 0;
for (i = 0; i < SIZE; i++)
printf("%c,", wRaceTrack[i]);
printf("\n\n");
if (harePtr = tortoisePtr)
printf("OUCH! Damn tortoise bit the hare!\n\n");
if (harePtr[69])
return 1;
else if (tortoisePtr[69])
return 2;
else
raceRunner(wRaceTrack, moveHare, moveTortoise);
}
void moveHare ( char *harePtr, int i) {
if (i == 1) {
*harePtr = '_';
harePtr - 12;
*harePtr = 'H';
}
if (2 <= i <= 3) {
return;
}
if (4 <= i <= 5){
*harePtr = '_';
harePtr + 9;
*harePtr = 'H';
}
if (6 <= i <= 8) {
*harePtr = '_';
harePtr + 1;
*harePtr = 'H';
}
if (9 <= i <= 10) {
*harePtr = '_';
harePtr - 2;
*harePtr = 'H';
}
}
void moveTortoise ( char *tortoisePtr, int i) {
if (1 <= i <= 5) {
*tortoisePtr = '_';
tortoisePtr + 3;
*tortoisePtr = 'T';
}
if (6 <= i <= 7){
*tortoisePtr = '_';
tortoisePtr - 6;
*tortoisePtr = 'T';
}
if (8 <= i <= 1) {
*tortoisePtr = '_';
tortoisePtr + 1;
*tortoisePtr = 'T';
}
}
What I'm trying to do is to then first set their CURRENT position back to '_', then increment each pointer to move up or down along the array accordingly, depending on what the random generator comes up with, and change that value to 'T' or 'H'. First pointer that points to the last element in the array, [69], wins the race.
When I run the program however, it consistently produces the same result each time, without the hare marker making an appearance anywhere on the array. I'm positive this is because I've my pointers set up improperly, as I'm still trying to wrap my head around the whole concept. Is it not possible to set up pointers to the same array? Or am I accessing the array in the wrong way through incorrect use of * and &? I'm honestly lost when it comes to using those operands to properly integrate pointers with arrays, so any and all help is appreciated. Thank you!
In your code, There are many issues.
First,
harePtr - 12;
...
harePtr + 9;
...
tortoisePtr + 3;
etc. statements are essentially useless. They do not affect harePtr or tortoisePtr, as you might have thought. The result of the opration is lost, unless you collect the same in some variable.
You can make use of += or -= in this regard, to modify the LHS operand value.
Second
regarding the chaining of relational operators, like
if (1 <= i <= 5)
see this answer to find out why it surprises you. is logically wrong.
Third
In your code
if (harePtr = tortoisePtr) –
does not compare the values, instead assigns it. You need to use == for comparison.
Fourth
srand() is used to seed the random number generator. You need to call srand() only once from the main(). You may want to refer to the related answer.
First of all, subtracting a number from a pointer will return a new value, not modify the existing one. Use the -= and += operators to actually change something.
Secondly, randomly changing a pointer and then using it without first checking whether it is still inside the valid range means the operating system will bite your program long before either animal manages to bite the other.
Related
When I run the following C code I get the values:
222222222
312222222
102222222
I was expecting the values:
222222222
31
10
Why does the char number[] defined in my intToStr function remember previous values? I thought once the function call ended all local data was more or less destroyed.
#include <stdio.h>
void intToStr(int n);
int main(void)
{
intToStr(222222222);
intToStr(31);
intToStr(10);
return 0;
}
void intToStr(int n)
{
char number[10];
int l = 0;
if (n < 0)
{
l++;
number[0] = '-';
n *= -1;
}
int nCopy = n;
while (nCopy > 9)
{
nCopy /= 10;
l++;
}
int r;
while (n > 9)
{
r = n % 10;
n /= 10;
number[l--] = r + '0';
}
number[l] = n + '0';
printf("%s\n", number);
}
the array should not remember the old data
For each program, the C standard either:
specifies what the program should do
says that it is not specified what the program should do
It hardly ever says that the program should not do something in particular.
In this case, the standard says that it is not specified what characters should be in the array at the start of the function. They can be anything at all. Characters from the previous call is one particular case of "anything at all".
That's undefined behavior. If only the first 3 character are set, it may print 312222222 or it may print 312???????????????????
The last characters in char number[10] are not initialized, that means the compiler may decide to leave it alone and the old values stay, or something else happens.
Otherwise printf doesn't know where the string end, it keeps printing until it randomly hits a zero.
If there is buffer overrun printf finds a different set of characters in memory (which we are not supposed to be accessing) and the program keeps printing those same characters until it randomly hits a zero and finally stops.
To fix it, simply make sure there is '\0' at the end. You can also add additional check to make sure the length does not exceed the buffer size
Working example:
char number[10];
int l = 0;
if (n < 0)
{
l++;
number[0] = '-';
n *= -1;
}
if (n < 0) return;
int nCopy = n;
while (nCopy > 9)
{
nCopy /= 10;
l++;
}
int len = l;
if (len + 1 > sizeof(number))
return;
number[len + 1] = '\0';
int r;
while (n > 9)
{
r = n % 10;
n /= 10;
number[l--] = r + '0';
}
number[l] = n + '0';
printf("%s\n", number);
Ok, so I am not looking for an a full answer please. I just don't know where to begin with this. I have a code that is declaring a pointer array full of names. The goal is to write a code to search the names and count each letter that is used.
/*
* Search through each character in s,
* which is array containing n strings,
* and update the global count array
* with the correct character counts.
* Note: check the examples to see
* if the counts should be case
* sensitive or case insensitive.
*/
void letterCount(char * s[], int n){
//Implement this function
int c = 0,x; // This is what I've done and I
char p = 'a', j = 'z'; // don't know where im messing up.
while (s[c] != '\0') { // I know I can't compare pointer
if (s[c] >= p && s[c] <= j ){ // and integer.
x = *s[c] - 'a';
count[x]++;
}
c++;
}
}
/*
* Initialize each value in the global
* count array to zero.
*/
void initializeCount(){
//Implement this function
int i;
for (i = 0; i < 26; i++){ // Also not sure if this is correct.
count[i] = 0;
}
}
The output should count the letter uses into an array called count[26].
Any suggestions please?
s[c] is not a character, it's a pointer, you are comparing pointer and character p which is not valid,
if (s[c] >= p && s[c] <= j ) // here you are comparing address & char, which you shouldn't
rotate one more loop for comparing each char of string.
Modify your code as
void letterCount(char * s[], int n){
//Implement this function
int c = 0,x,i; // This is what I've done and I
char p = 'a', j = 'z'; // don't know where im messing up.
// assuming n is no of string, rotate main loop from 0 to n
while (c<n) {
for(i=0;s[c][i]!='\0';i++) // I know I can't compare pointer
if (s[c][i] >= p && s[c][i] <= j ){ // and integer.
x = s[c][i] - 'a';
count[x]++;
}
c++;
}
}
I hope you got this.
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.
I have the code as:
mid = 3;
for(i=0;i<9;i++)
{
if(i == 9-mid)
num[i] = mid;
else
num[i] = 0;
printf("%d", num[i]);
}
which gives the result of "000000300".
What I try to do is to store "000000300" as an element of another array, i.e.
unsigned int array[0] = 000000300;
Any ideas of how to do this in C? Thanks~
If you want to copy the calculated string "000000300" you will need to allocate some memory and store it in a char * array:
// num is a char array containing "000000300".
char *stored = (char *)malloc(strlen(num) + 1);
if (stored == NULL) {
// This means that there is no memory available.
// Unlikely to happen on modern machines.
}
strcpy(stored, num);
I'm trying to write a program that will receive 2 strings representing numbers of any length
(for instance, char *a = "10000000000000";, char *b = "9999999999999999";) and multiply them.
This is what I came up with so far, not sure how to continue (nullify simply fills the whole string with '0'):
char *multiply(char *hnum, const char *other)
{
int num1=0, num2=0, carry=0, hnumL=0, otherL=0, i=0, temp1L=0, temp2L=0, n=0;
char *temp1, *temp2;
if(!hnum || !other) return NULL;
for(hnumL=0; hnum[hnumL] != '\0'; hnumL++);
for(otherL=0; other[otherL] != '\0'; otherL++);
temp1 = (char*)malloc(otherL+hnumL);
if(!temp1) return NULL;
temp2 = (char*)malloc(otherL+hnumL);
if(!temp2) return NULL;
nullify(temp1);
nullify(temp2);
hnumL--;
otherL--;
for(otherL; otherL >= 0; otherL--)
{
carry = 0;
num1 = other[otherL] - '0';
for(hnumL; hnumL >= 0; hnumL--)
{
num2 = hnum[hnumL] - '0';
temp1[i+n] = (char)(((int)'0') + ((num1 * num2 + carry) % 10));
carry = (num1 * num2 + carry) / 10;
i++;
temp1L++;
}
if(carry > 0)
{
temp1[i+n] = (char)(((int)'0') + carry);
temp1L++;
}
p.s. Is there a library that handles this already? Couldn't find anything like it.
On paper, you would probably do as follows:
999x99
--------
8991
8991
========
98901
The process is to multiply individual digits starting from the right of each number and adding them up keeping a carry in mind each time ("9 times 9 equals 81, write 1, keep 8 in mind"). I'm pretty sure you covered that in elementary school, didn't you?.
The process can be easily put into an algorithm:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct result
{
int carry;
int res;
};
/*
* multiply two numbers between 0 and 9 into result.res. If there is a carry, put it into
* result.carry
*/
struct result mul(int a, int b)
{
struct result res;
res.res = a * b;
if (res.res > 9)
{
res.carry = res.res / 10;
res.res %= 10;
}
else
res.carry = 0;
return res;
}
/*
* add
* adds a digit (b) to str at pos. If the result generates a carry,
* it's added also (recursively)
*/
add(char str[], int pos, int b)
{
int res;
int carry;
res = str[pos] - '0' + b;
if (res > 9)
{
carry = res / 10;
res %= 10;
add(str, pos - 1, carry);
}
str[pos] = res + '0';
}
void nullify(char *numstr, int len)
{
while (--len >= 0)
numstr[len] = '0';
}
int main(void)
{
struct result res;
char *mp1 = "999";
char *mp2 = "999";
char sum[strlen(mp1) + strlen(mp2) + 1];
int i;
int j;
nullify(sum, strlen(mp1) + strlen(mp2));
for (i = strlen(mp2) - 1; i >= 0; i--)
{
/* iterate from right over second multiplikand */
for (j = strlen(mp1) - 1; j >= 0; j--)
{
/* iterate from right over first multiplikand */
res = mul((mp2[i] - '0'), (mp1[j] - '0'));
add(sum, i + j + 1, res.res); /* add sum */
add(sum, i + j, res.carry); /* add carry */
}
}
printf("%s * %s = %s\n", mp1, mp2, sum);
return 0;
}
This is just the same as on paper, except that you don't need to remember individual summands since we add up everything on the fly.
This might not bee the fastest way to do it, but it doesn't need malloc() (provided you have a C99 compiler, otherwise you would need to dynamically allocate sum) and works for arbitrarily long numbers (up to the stack limit since add() is implemented as recursive function).
Yes there are libraries that handle this. It's actually a pretty big subject area that a lot of research has gone into. I haven't looked through your code that closely, but I know that the library implementations of big num operations have very efficient algorithms that you're unlikely to discover on your own. FOr example, the multiplication routine we all learned in grade school (pre common-core) is a O(n^2) solution to multiplication, but there exist ways to solve it in ~O(n^1.5).
THe standard GNU c big num library is GNU MP
https://gmplib.org/