Iterating over C string not working - c

First, my objective with this code: take in a sentence into a C string. Iterate through the sentence and see how many instances of a particular letter occur.
This code is working somewhat but not giving the right number? Not sure why:
#include <stdio.h>
#include <string.h>
int tracker=0;
int letterCount (char *sentence)
{
int s=strlen(sentence);
int i=0;
for (i=0; i<s; i++){
if (sentence[i]=='h') {
tracker++;
}
}
return tracker;
}
int main(int argc, const char * argv[])
{
char *string="Hi there, what's going on? How's it going?";
letterCount(string);
printf("this sentensce has %i H's", tracker);
return 0;
}
The output I'm getting:
this sentensce has 2 H's
Not quite right. Any ideas?

This is the correct code if you mean case insensitive H:
#include <stdio.h>
#include <string.h>
int tracker=0;
int letterCount (char *sentence)
{
int s=strlen(sentence);
int i=0;
for (i=0; i<s; i++){
if (sentence[i]=='h' || sentence[i]=='H') { //'h' is not the same as 'H'
tracker++;
}
}
return tracker;
}
int main(int argc, const char * argv[])
{
char *string="Hi there, what's going on? How's it going?";
letterCount(string);
printf("this sentensce has %i H's", tracker);
return 0;
}
You have just mispelled small and the capital letter in your code.
Remember, the C language is case sensitive!

Although your label talks about the number of Hs, your letterCount looks for hs instead -- and it looks to me like the input you've provided does have two instances of lower-case h, just as it says.
If you want to count them together, you might consider filtering each input with tolower or toupper before checking what you have.

That number looks correct to me: you have 2 'h' characters in that sentence. If you want to count the 'H' characters as well, then you need a separate check.

size_t letterCount(const char* sentence, char c)
{
size_t count = 0;
while(sentence)
{
count += (*sentence == c);
++sentence;
}
return count;
}
What do we see here?
You can't have negative count, so use an unsigned type like size_t
sentence shouldn't be modified, so it should be const
pass in the char you want to match
sentence is a pointer, if it is null you are done. Don't need to call strlen.
sentence is a pointer, the actual pointer is pass by value, so you can modify it (see the increment, no need to make an extra variable)
boolean operators return 1 or 0, so no need to use the if. (Although, I haven't looked at the assembly to see if an if branch or an add 0 is cheaper. YMMV)

Related

I am doing an assignment that asks me to make a function that creates an acronym from a string, then return the acronym

The prompt that I'm given is: An acronym is a word formed from the initial letters of words in a set phrase. Write a program whose input is a phrase and whose output is an acronym of the input. If a word begins with a lower case letter, don't include that letter in the acronym. Assume there will be at least one upper case letter in the input.
Also, I am given the following function to use: void CreateAcronym(char userPhrase[], char userAcronym[]).
My problem with the code is that only the first letter is being saved to the userAcronym variable.
For example, when the string is Institute of Electrical and Electronics Engineers. The output I'm getting is just I. What do I need to change to get the remaining letters?
Thank you for the help.
My code so far is:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 60
void CreateAcronym(char userPhrase[], char userAcronym[]){
int i;
int j=0;
for(i = 0; i < strlen(userPhrase); ++i){
if(isupper(userPhrase[i])){
userAcronym[j]=userPhrase[i];
}
j++;
}
printf("%s", userAcronym);
}
int main(void) {
char phrase[MAX];
char acronym[10];
fgets(phrase, MAX, stdin);
CreateAcronym(phrase, acronym);
return 0;
}
For starters the function CreateAcronym should be declared at least like
void CreateAcronym( const char userPhrase[], char userAcronym[]);
because the passed string that contains a phrase is not being changed within the function.
But it will be even better to declare the function like
char * CreateAcronym( const char userPhrase[], char userAcronym[]);
The function should not output anything. It is the caller of the function that decides whether to output the acronym formed within the function.
The function invokes undefined behavior because the array acronym does not get a string.
Moreover there is another bug in the for loop
for(i = 0; i < strlen(userPhrase); ++i){
if(isupper(userPhrase[i])){
userAcronym[j]=userPhrase[i];
}
j++;
}
where the variable j is incremented in each iteration of the loop.
And calling the function strlen in the condition of the loop is inefficient.
Also the function does not copy only initial upper case letters of words to the destination array. It tries to copy any upper case letter. So the for loop in any case does not make a sense.
The function can be defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
char * CreateAcronym( const char userPhrase[], char userAcronym[] )
{
char *p = userAcronym;
while ( *userPhrase )
{
while ( isspace( ( unsigned char )*userPhrase ) ) ++userPhrase;
if ( isupper( ( unsigned char )*userPhrase ) ) *p++ = *userPhrase;
while ( *userPhrase && !isspace( ( unsigned char )*userPhrase ) ) ++userPhrase;
}
*p = '\0';
return userAcronym;
}
int main(void)
{
const char *phrase = "Institute of Electrical and Electronics Engineers";
char acronym[10];
puts( CreateAcronym( phrase, acronym ) );
return 0;
}
The program output is
IEEE
Try it. First, you used j++ not in "if". And second, you didnt put '\0' in your userAcronym string. '\0' means that your string end here and all string will be printed before this symbol.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 60
void CreateAcronym(char userPhrase[], char userAcronym[]){
int i;
int j = 0;
for(i = 0; i < strlen(userPhrase); i++){
if(isupper(userPhrase[i])){
userAcronym[j] = userPhrase[i];
j++;
}
}
userAcronym[j] = '\0';
printf("%s", userAcronym);
}
int main(){
char phrase[MAX];
char acronym[10];
fgets(phrase, MAX, stdin);
CreateAcronym(phrase, acronym);
return 0;
}

Why the code below excutes unexpected letters in the end of the string?

This is my code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int countNumber(char string[],int number_[]);
int countNumber(char string[]);
int main(){
char string[] = "tran_huynh_minh_phuc";
int num = countNumber(string)+1;
int *number = (int *) calloc(num, sizeof(int));
countNumber(string,number);
for(int i=0;i<num;i++){
printf("%d\n",number[i]);
}
fflush(stdin);
char a[3][14];
strncpy(a[2], string+5, 5);
printf("%s",a[2]);
}
int countNumber(char string[],int *number)
{ int count=0;
int num_i=1;
number[0]=-1;
for(int i=0; i<strlen(string); i++)
{
if(string[i]=='_')
{ number[num_i] = i;
num_i++;
}
}
return count;
}
int countNumber(char string[])
{ int count=0;
for(int i=0; i<strlen(string); i++)
{
if(string[i]=='_')
{
count++;
}
}
return count;
}
this is my problem console results:
I am doing the program to get the substring which will get "tran","huynh","minh" from "tran_huynh_minh", however it is appearing some unexpected letters at the end of my substring. In addition, I tried many ways to fix it but it did not work. Can you find my mistakes?
Thanks
Minh Phuc
I think the intent for the bottom of the main block is something like this (this adds the null after the 'huynh' which was copied. By adding the null, when it goes to print a2, it knows when to stop. It looks like the desire was to put the second word in the array at index 2 (presumably being done in a loop once it was working or the like):
strncpy(a[2], string + 5, 5);
a[2][5] = '\0';
printf("%s", a[2]);
If you run something equivalent to this, you should see the expected output. However, you likely also see a warning on the strncpy function and considering using strncpy_s (depending what you are using to compile. It looks like you are on windows). If you replace the function call with strncpy_s (assuming Visual Studio), you will get the desired result without adding the null at the end separately. Note it expects a size of the destination array as a safeguard (14 in this case).
See this link as well as this one.

Error with the array returning through function

I need to read a word from main function and convert the characters in UCASE if the first character is LCASE and vice versa using the user defined function.I tried ways for returning the array from function but still I am lacking some core ideas. Please debug this program and explain the way it works.
#include <stdio.h>
#include <string.h>
int* low (char str)
{
int i;
for (i=1; i<strlen(str);i++)
{
if(str[i]<91)
{
str[i]=str[i]+32;
}
else
{
}
}
return &str;
}
int* high (char str[50])
{
int i;
for (i=0; i<strlen(str);i++)
{
if(str[i]>91)
{
str[i]=str[i]-32;
}
else
{
}
}
return &str;
}
void main()
{
char str[50];
char* strl;
printf("Enter any string....\n");
scanf("%s",str);
if (str[0]<91)
{
*strl=low(str);
}
else
{
*strl=high(str);
}
printf("Converted string is %s.",*strl);
}
There is already a problem here:
So if you are saying this code is perfect and you want us to debug it and explain how (on earth) this works, then here you go.
In function int* low (char str), you have if(str[i]<91). Thats a problem right there. str is a char received as an argument, and hence str[i] is a straight compile-time error.
Another one to deal with is the return statement.
You have a statement:
return &str;
which would return the address of str, which by the way is a char, whereas function low is supposed to return a pointer to an int.
The same is applicable to high function as well.
Suggestion: Leave aside this bad code and get a beginner level C programming book first. Read it and the try some codes out of it.
A few inputs for improvement: (Which you may not comprehend)
change
void main()
to
int main(void)
Why? Refer this legendary post: What should main() return in C and C++?
Secondly, int both functions you are using strlen() in loop which will always return a fixed value. So, instead of
for (i=0; i<strlen(str);i++)
I'd suggest,
size_t strlength = strlen(str);
for (i=0; i < strlength; i++)
You can try the code and method as below:
#include <stdio.h>
#include <string.h>
char* caseConverter (char *str)
{
int i;
for (i=0; i<strlen(str);i++)
{
if(str[i]>=65 && str[i]<=90)
{
str[i]=str[i]+32; //To lower case
}
else if((str[i]>=97 && str[i]<=122))
{
str[i]=str[i]-32; //To upper case
}
else
printf("%c is not an alphabet \n",str[i]);
}
return str;
}
void main()
{
char inputStr[50]= "Stubborn";
char* opStr= caseConverter(inputStr);
printf("Converted string is %s",opStr);
}

Why isn't isalpha working?

I'm working with C and I need to check that the user inputed second command line argument argv[1] is made up of only alphabetical charchaters and if not, to do what is inside the else loop. I used the is alpha function but when i compile and run the program no matter what my second command line argument is (alphabetical or otherwise), its always executing the "else loop". How do i fix this?
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int a = argc;
if (a != 2)
{
return 1;
}
string b = argv [1];
int c = strlen(b);
string m;
for (int i = 0; i < c; i++)
{
if (isalpha(b[c]))
{
m = GetString();
}
else
{
printf("Please provide a valid keyword\n");
return 1;
}
}
}
Try replacing
if (isalpha(b[c]))
with
if (isalpha(b[i]))
Currently you are checking the element at the index which is the result of strlen(b) at every iteration of your loop. Because array indices are zero based in C b[strlen(b)] is referencing '\0', the null terminator.
In reference to the Keith Thompson comment below and the answer to this question you should actually be casting the value passed to isalpha to an unsigned char to ensure that undefined behaviour is not invoked.
Thus you should change your code to
if (isalpha((unsigned char)b[i]))
to ensure there is no UB
Use isalpha(b[i]) instead of isalpha(b[c])
like this:
if (isalpha(b[i]))
{
m = GetString();
}

The showbits() function

While reading a book called "Let us C" I read that a function showbit() exists which can show you the bits of the number. There wasn't any special header file mentioned for it. Searched for it on the internet and didn't found anything useful. Is there such a function? I want this to print the binary of decimal numbers. Else please give me a replacement function. Thanks
All integers are actually in binary in your computer. Its just that it is turned into a string that is the decimal representation of that value when you try to print it using printf and "%d". If you want to know what it looks like in some other base (e.g. base 2 or binary), you either have to provide the proper printf format string if it exists (e.g. "%x" for hex) or just build that string yourself and print it out.
Here is some code that can build the string representation of an integer in any base in [2,36].
#include <stdio.h>
#include <string.h>
char digits[]="01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
void reverse(char* start, char* end)
{
for(end--;start<end;start++,end--)
{
char t=*start;
*start=*end;
*end=t;
}
}
int base_change(int n, int base,char* buffer)
{
int pos=0;
if (base>strlen(digits))
return -1;
while(n)
{
buffer[pos]=digits[n%base];
n/=base;
pos++;
}
buffer[pos]='\0';
reverse(buffer,buffer+pos);
return 0;
}
int main()
{
char buffer[32];
int conv=base_change(1024,2,buffer);
if (conv==0) printf("%s\n",buffer);
return 0;
}
You can also try this snippet which uses bit-shifting:
EDIT: (I've made it more portable)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BITS_IN_BYTE 8
#define INTEGRAL_TYPE unsigned int
void showBits(INTEGRAL_TYPE x) {
int i;
static int intSizeInBits = sizeof(INTEGRAL_TYPE) * BITS_IN_BYTE;
static char symbol[2] = {'0','1'};
char * binary = (char*) malloc(intSizeInBits + 1);
memset(binary, 0, intSizeInBits + 1);
for (i=0; i< intSizeInBits; i++) {
binary[intSizeInBits-i-1] = symbol[(x>>i) & 0x01];
}
printf("%s\n", binary);
free(binary);
}
int main() {
showBits(8698513);
return 0;
}
HTH!
This is a very simple solution for printing the bits of an integer
int value = 14;
int n;
for (n=8*sizeof(int)-1;n>=0;n--) {
printf("%d",(value >>n)&1);
}
The book "Let Us C" doesn't define it as a built-in function. The showbits() function is defined in later part of the book as a complete user defined function as I personally went through it. This answer is to anyone who haven't reached that later part of the book and are stuck at the first appearance of the function in the book.
you need to look here
#downvoter It works fine in c also. You just need to reformat your code in c-style.
#include <stdlib.h>
#include <stdio.h>
int main()
{
char buffer[20];
int i = 3445;
_itoa( i, buffer, 2 );
printf("String of integer %d (radix 2): %s",i,buffer);
return 0;
}
*you need to save your file as .c in MSVC++ for _itoa() to work.*
this is the header file for showbits
void showbits(unsigned int x)
{
int i;
for(i=(sizeof(int)*5)-1; i>=0; i--)
(x&(1u<<i))?putchar('1'):putchar('0');
printf("\n");
}
No there is no pre built function and you do not need to include any specific header file.
You will have to provide implementation for function showbits(int).
#include <stdio.h>
void showbits(int);
int main()
{
int j,k;
for(j=0;j<=11;j++)
{
printf("\nBinary value of decimal %d is :",j);
showbits(j);
}
return 0;
}
showbits(int n){
int i,k,andmask;
for(i = 15;i>=0;i--){
andmask = 1<<i;
k = n & andmask;
k==0 ? printf("0"):printf("1");
}
}
If you want to print out the bits of a float, for example you could do something like:
float myFloat = 45.2;
for (int n=0;n<8*sizeof(float);n++) {
printf("%d",(myFloat>>n)&1);
}

Resources