Searching through pointer array to count letter uses - c

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.

Related

Why is the pointer to pointer arithmatic failing in my conditional statment?

sm is a 2D array of character pointers allocated dynamically. I need to understand why my pointer to pointer arithmetic is failing in conditional if in loop structure.
2nd column in sm is where the string is that I need to test with the grade key gk which is array of characters/string. s holds row size and q is column size for 2D array, hm is my heap memory counter for freeing function which is not importing for my question.
double *cals(char **sm, char *gk, int s, int q, unsigned *hm) {
int c = 0;
double *savg = malloc(s * sizeof(double));
assert(savg);
*hm += 1;
for (int i = 0; i < s; *(savg + i) = c / q * 100 , c = 0, ++i) {
for (int j = 0; j < q; ++j) {
if (*(*(sm + i * STUDENTATT + 1) + j) == *(gk + j))
++c;
}
}
return savg;
}
There isn't much information given about the purpose of cals function so I had to make a few assumptions to write this answer.
Assumption-1(meaningful):-
You want to find how much characters in the two strings are equal(no every characters) and then find the percentage of the same characters to the total characters. If that is the case use the below code.
double *cals(char **sm, char *gk, int s, int q, unsigned *hm) {
float c = 0; // To force float division the c is declared as a float variable
double *savg = malloc(s * sizeof(double));
assert(savg);
*hm += 1;
char* sm_i_key = NULL;
unsigned int strlen_gk = strlen(gk);
unsigned int key_length = string_gk;
for (int i=0; i<s; ++i) { //The calculation is moved inside for loop
sm_i_key = *(sm+i*q+1); // You can also use sm_i_key = &sm[i*q+1]
/* Uncomment this section if length of 2 strings are not bound to be equal
if(strlen(sm_i_key) < strlen_gk){
key_length = sm_i_key;
}
else{
key_length = strlen_gk
}
*/
for (int j = 0; j < key_length; ++j) {
if (sm_i_key[j] == gk[j])
++c;
}
savg [i] = c / strlen_gk * 100; /* Since gk is the grade key it is assumed
to be equal to the total number.*/
c = 0;
}
return savg;
}
Assumption-2:-
You want to check whether the strings whose starting address is stored in the second column of each row of a 2D array sm is equal to the string stored in array pointed by gk and then calculate a value(double).
The function cals only returns 0.0 or 100.0 as the formula avgs[i]=c / q * 100 will only produce 0 if stings are not equal(since integer division c/q will always result in 0 if c is less than q which is the case here) and 100 if strings are equal(Then why use a double to store the value if only 0 and 100 is stored).
If that is the case then what you are doing here is fine unless the array gk and array sm[i][2] have different string length(not q). It would be better to use strncmp to check the equality of string if the string length of two array's are bound to be different.
Use the below code to do that:-
double *cals(char **sm, char *gk, int s, int q, unsigned *hm) {
int c;
char* sm_i_key = NULL;
double *savg = malloc(s * sizeof(double));
assert(savg);
*hm += 1;
for (int i=0; i < s;++i){//The calculation is moved to a static assignment given below
if(strncmp(sm_i_key, gk, strlen(gk) == 0)
{
savg[i] = 100.0; // Since c/q * 100 => 100.0 if q == c
}
else
{
savg[i] = 0.0; /*Since c/q *100 => 0.0 if q < c since integer
division will result in 0.*/
}
}
return savg;
}
I hope it helps.

Tortoise and the Hare Pointers

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.

Finding the most frequent character in a file in C

I'm writing a function that finds the most common alphabetic character in a file. The function should ignore all characters other than alphabetic.
At the moment I have the following:
int most_common(const char *filename)
{
char frequency[26];
int ch = 0;
FILE *fileHandle;
if((fileHandle = fopen(filename, "r")) == NULL){
return -1;
}
for (ch = 0; ch < 26; ch++)
frequency[ch] = 0;
while(1){
ch = fgetc(fileHandle);
if (ch == EOF) break;
if ('a' <= ch && ch <= 'z')
frequency[ch - 'a']++;
else if ('A' <= ch && ch <= 'Z')
frequency[ch - 'A']++;
}
int max = 0;
for (int i = 1; i < 26; ++i)
if (frequency[i] > frequency[max])
max = i;
return max;
}
Now the function returns how many times the most frequent letter occurred, not the character itself. I'm a bit lost, as I'm not sure if that's the way this function should look like at all. Does it make sense and how possibly can I fix the problem?
I would really appreciate your help.
The variable frequency is indexed by the character code. So frequency[0] is 5, if there have been 5 'a's.
In your code you are assigning the count to max, not the character code, so you're returning the count not the actual character.
You need to store both the maximum frequency count and the character code that it referred to.
I would fix this with:
int maxCount = 0;
int maxChar = 0;
// i = A to Z
for (int i = 0; i <= 26; ++i)
{
// if freq of this char is greater than the previous max freq
if (frequency[i] > maxCount)
{
// store the value of the max freq
maxCount = frequency[i];
// store the char that had the max freq
maxChar = i;
}
}
// character codes are zero-based alphabet.
// Add ASCII value of 'A' to turn back into a char code.
return maxChar + 'A';
Note that I changed int i = 1 to int i = 0. Starting at 1 would mean starting at B, which is a subtle bug you might not notice. Also, the loop should terminate at <= 26, otherwise you'd miss out Z too.
Note the braces. Your braces style (no braces for single-statement blocks) comes very highly un-recommended.
Also, i++ is more common than ++i in cases like this. In this context it will make no difference, so would advise i++.

Getting a value from a char array

I have written a function below to take a char array and manipulate its values (namely, convert the char to an int if it is a number). However, I have a question with how the char array is managed. When I look at input[i], it is the correct value (the value that was placed in the array. However, &input[i] gives a capital letter, and I don't know why it does that. For example, if I enter "11" and trace the variables, I might get the following result:
input[0] is 1
&input[0] is D
input[1] is 1
&input[1] is E
On to my code, if I try to use input[i], I get the error of "passing argument makes pointer from integer without cast". If I use &input[i], the code compiles but I get the wrong result. What's going on with this, and how do I access the value I'm trying to get?
Below is my code:
void myFunction(char *input) {
Queue* numberQueue = queue_new();
Queue* opQueue = queue_new();
int i = 0;
int j;
for (j = 0; j < strlen(input); j++) {
printf("input[%d] is %c\n", i, input[i]);
printf("&input[%d] is %c\n", i, &input[i]);
int number = (int)input[i];
/* queue_push_tail(queue, data) */
queue_push_tail(numQueue, number); /* ERROR */
/* rest of code omitted */
i++;
}
}
If I understand that you want to push each digit in the input character string into queue_push_tail, as an integer value then you want your loop to do something like this:
for (j = 0; j < strlen(input); j++) {
if ( input[j] >= '0' && input[j] <= '9')
{
number = input[j] - '0';
/* queue_push_tail(queue, data) */
queue_push_tail(numQueue, number); /* ERROR - FIXED*/
/* rest of code omitted */
}
}
Recall, ASCII characters are themselves unsigned integers. You simply need to adjust the value for each character by subtracting the value of ASCII '0'. If you need to collect all numbers from the string into a single number (e.g. ac7f9gh3 => 793) then simply store the values unadjusted in a temp string, and then call atoi (temp).

Using histogram to find the most common letter in an array

This is what I came up with, but I always get a Run-Time Check Failure #2 - Stack around the variable 'h' was corrupted.
int mostCommonLetter(char s[]) {
int i=0, h[26],k=0, max=0, number=0;
while ( k < 26){
h[k] = '0';
k++;
}
while(s[i] != '\0'){
h[whichLetter(s[i])] = h[whichLetter(s[i])]+1;
i++;
}
h[26] = '\0';
for(i=0;h[i]!='\0';i++){
if(h[i] > max)
number=i;
}
return number;
}
You cannot do h[26] = '\0'; - h has 26 elements indexed 0..25. As you know the length of h you don't need to 0-terminate it, simply do for (i=0; i < 26; ++i)
Also, are you certain whichLetter always returns a value in the 0..25 range? What does it do if it e.g. encounters a space?
This writes past the end of the array:
h[26] = '\0';
Make the for loop depend on the length rather than the last character:
for(i=0;i<26;i++){
if(h[i] > max)
number=i;
}

Resources