I'm trying to count spaces using c strings. I can't use std strings. And on the line comparing the two chars I get the error 'invalid conversion from 'char' to 'const char*'.
I understand that I need to compare two const chars* but I'm not sure which one is which. I believe sentence[] is the char and char space[] is const char* is that right? And I need to use some sort of casting to convert the second but I'm not understanding the syntax I guess. Thanks for the help <3
int wordCount(char sentence[])
{
int tally = 0;
char space[2] = " ";
for(int i = 0; i > 256; i++)
{
if (strcmp(sentence[i], space) == 0)
{
tally++
}
}
return tally;
}
If you really want to count space characters, I think the following method would be better, since it checks where char array ends. A string terminator(\0) signals the end of the char array. I don't know why you hard-coded 256.
int countSpaceCharacters(char* sentence)
{
int count = 0;
int i = 0;
while (sentence[i] != '\0')
{
if (sentence[i] == ' ')
{
count++;
}
i++;
}
return count;
}
However, if you want to count words as I can see from the original method name, you need to think a better way. Because this algorithm would fail in non-perfect situations such as having consecutive space characters or punctuation marks that have no space character around them etc.
strcmp is used to compare two character strings not a single character with one character string.
there is no function: strcmp(char c, char*); // if there's it's illogical!
if you want to search for a single character in a character string just compare this character with all elements using iteration:
iint wordCount(char* sentence)
{
int tally = 0;
char space[2] = " ";
for(int i = 0; i < strlen(sentence); i++)
{
if (sentence[i] == space[0])
{
tally++;
}
}
return tally;
}
Might i suggest this:
for(int i = 0; i < 256; i++) {
if (isspace(sentence[i])) // or sentence[i] == ' '
{
tally++
}
}
What you are trying to do now is compare a char (sentence[i]) with a c-string (space) which wont work.
Note that your implementation wont do what you expect for sentences like
"a big space be in here."
So you need to think about what to do for multiple spaces.
Related
I'm new to C and need to parse the string "var1=bob&var2=j" that I am passing into a function as a char pointer. I would like to just return a char array such as ["bob","smith"].
I'm having a bit of trouble with the C syntax and have not been able to successfully loop over the input and extract out "bob" and "smith" in this case by parsing it. I have been trying to mess around with strtok() but unsuccessfully.
If anyone could help me out here it would be much appreciated.
Thank you.
strtok won't work since the delimiter is changing (&var2=, &var3=).
The basic program to print out the names is simple.
int main() {
char* str = "var1=bob&var2=smith";
// iterate all characters
for (int i = 0; i < str[i] != '\0'; i++) {
// if equal is found, you have your word
if (str[i] == '=') {
// keep iterating the characters upto & or \0
for (int j = i+1; str[j] != '\0' && str[j] != '&'; j++) {
printf("%c", str[j]);
}
printf("\n");
}
}
return 0;
}
You will need to create a char* array to store those names.
I would treat this problem by first splitting the input string into tokens on the ampersand ("&"), then split each of the individual tokens on the equal sign ("=").
I mostly work in C#, where this would be trivial:
string[] tokens = ("var1=bob&var2=smith").Split('&');
foreach (string s in tokens)
{
string[] parts = s.Split('=');
Console.Write(parts[0] + " = " + parts[1]);
}
I'm studying elementary programming in C and I'm doing a challenge to determine the reading age of various sentences. This is achieved by determining the amount of sentences in a string etc. I have some code that does the my first very basic step but it's not quite working as expected.
I'm thinking this is because my knowledge of the strlen function etc isn't sufficient.
I don't want to cheat for the answer as I like the sense of achievement from the problem solving. But would it be possible to get a gentle push in the right direction if at all possible?
char sentence[] = "One fish. Two fish. Red fish. Blue fish.";
int main(void)
{
int sentence_count = 0;
int word_count = 0;
int i;
int length = strlen(sentence);
for (i = 0; i == strlen(sentence); i++) //need to somehow go through a string one char at a time until the end.
{
if (sentence[i] == '.' || sentence[i] == '!' || sentence[i] == ';' || sentence[i] == '?')
{
return sentence_count ++;
}
if (sentence[i] == '\0')
{
return word_count ++;
}
}
printf("There are %i in %i sentences.\n", word_count, sentence_count);
printf("%i\n", length);
}
First Problem -
for (i = 0; i == strlen(sentence); i++)
This state should be -
for (i = 0; i < strlen(sentence); i++)
In your case, it would be terminating on the first iteration itself. However, You need to loop until you have reached the index - strlen(sentence).
Do recall that for loop has syntax - for(initialisation; condition; increment/decrement) will run only until the condition evaluates to true. So, you need the condition to evaluate to true till you have traversed the whole string which is done by the second line of code mentioned above.
A better alternative approach would be -
for (i = 0; sentence[i] != '\0'; i++)
which means the loop will run until you encounter a null-terminated character.
Second Problem -
return sentence_count ++;
.
.
return word_count ++;
Here, you don't need to add the return keyword before the above two statements. The return will directly exit from your program. Simply writing sentence_count++ and word_count++ would be correct.
Third Problem -
sentence[i] == '\0'
This statement doesn't quite fit with the logic that we are trying to achieve. The statement instead must check if the character is a space and then increment the word count -
if (sentence[i] == ' ')
{
return word_count ++;
}
Your for loop condition is the main problem; for (i = 0; i == strlen(sentence); i++) reads as "on entry, set i to 0, enter the body each time i is equal to the length of sentence, increment i at the end of each loop". But this means the loop never runs unless sentence is the empty string (has strlen of 0). You want to test i < strlen(sentence) (or to avoid potentially recomputing the length over and over, use the length you already calculated, i < length).
You also need to remove your returns; the function is supposed to count, and as written, it will return 0 the instant it finds any of the target characters, without using the incremented values in any way. Put a return 0; at the end of main to indicate exiting successfully (optionally, stdlib.h can be included so you can return EXIT_SUCCESS; to avoid magic numbers, but it's the same behavior).
The information in others answers being already covered, here are a couple of other suggestions for your consideration.
Remove function calls, such as strlen() from within the for(;;) loop. You've already obtained the length with:
int length = strlen(sentence);
Now, just use it in your for loop:
for(i = 0; i < length ; i++)//includes replacement of == with <
Encapsulate the working part of your code, in this case the the counting of words and sentences. The following uses a different approach, but its the same idea:
//includes deliminators for common end-of-sentence punctuation:
int count_sentences(const char *buf)
{
const char *delim = {".?!"};//add additional 'end-of-sentence' punctuation as needed.
char *tok = NULL;
int count = 0;
char *dup = strdup(buf);//preserve original input buffer
if(dup)
{
tok = strtok(dup, delim);
while(tok)
{
count++;
tok = strtok(NULL, delim);
}
free(dup);
}
return count;
}
One additional idea, that is out of scope with your original code, but very useful in practice is to remove any parts of the buffer that may not be part of the sentence, i.e. leading or trailing space. In your example, you have the test case for your sentences tightly defined within a string literal:
char sentence[] = "One fish. Two fish. Red fish. Blue fish.";
This is not incorrect, but what would happen at some point your code were to be expected to work with string buffers not so neatly packaged? i.e. leading or trailing white space characters in the buffer to be processed?
"\n\n\tOne fish. Two fish. Red fish. Blue fish.\f"
Removing unknown and unwanted content from the buffer prior to processioning simplifies the code doing the work, in this case counting sentences. Following is a simple example of how this can be done.
//prototype:
char *new = clear_leading_trailing_whitespace(sentence);
char * clear_end_space(const char *buf)
{
char *new = buf;
//clear leading whitespace
while (isspace(*new))
{
new++;
}
//clar trailing whitespace
int len = strlen(new);
while(isspace(*(new + len-1)))
{
len--;
}
*(new + len) = 0;
return buf;
}
Next, the following code segment is intending to count words:
if (sentence[i] == '\0')
{
return word_count ++;
}
But after being initialized to 0, word_count is only incremented once when seeing the null terminator, \0 once. Word count is generally a count of spaces between non-sentence terminating and non-whitespaces characters in a buffer. Or in otherwords, tracking how many clusters of non-whitespace there are. The following is a way to do this:
void countwords(const char *text, *count)
{
bool reading_word = false; // Flag
int words = 0;
for(int i=0; i<strlen(text); i++)
{
if(isspace(text[i])) {
reading_word = false;
}
else if(isalpha(text[i])) {
if(!reading_word) {
reading_word = true;
words++;
}
}
}
*count = words;
}
Functions like this can be used to greatly simplify contents of the main function:
char sentence[] = "One fish. Two fish. Red fish. Blue fish.";
int main(void)
{
int sentence_count = 0;
int word_count = 0;
char *new = clear_leading_trailing_whitespace(sentence);
countwords(new, &word_count);
sentence_count = count_sentences(new);
...
printf("There are %d words in %d sentences.\n", word_count, sentence_count);
}
I did this program to reverse the order of the words in the give string. (And it works)
i.e. Output: sentence first the is This
However I am stuck when it comes to adding another sentence to the array.
For example I need to have an array {"This is the first sentence", "And this is the second"} producing as output: sentence first the is This , second the is this And
int main() {
char str[] = {"This is the first sentence"};
int length = strlen(str);
// Traverse string from end
int i;
for (i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
// putting the NULL character at the position of space characters for
next iteration.
str[i] = '\0';
// Start from next character
printf("%s ", &(str[i]) + 1);
}
}
// printing the last word
printf("%s", str);
return 0;
}
I am new to C so its not surprising that I got stuck even if the solution is quite easy. Any help would be appreciated! Thanks!
Since you already have the code to print the words of one string in reverse order, I would suggest making that a function which takes a single string as an argument, i.e.:
void print_words_reverse(char * const str) {
// your current code here
}
Then you can call it separately for each string:
char strings[][30] = {
"This is the first sentence",
"And this is the second"
};
for (int i = 0; i < sizeof(strings) / sizeof(*strings); ++i) {
print_words_reverse(strings[i]);
}
Note that since you are modifying the string (by replacing spaces with NUL bytes), the argument needs to be modifiable, which means you are not allowed to call it (in standard C) with a pointer to a string literal, which means you can't simply use const char *strings[] = { "first", "second" }. You could get rid of the ugly constant length (here 30) reserved for every string by making your code not modify the argument string. Or you could have a separate char array for each sentence and then use pointers to those (modifiable) strings.
First, you can try with a two-dimensional array or use an array of pointers.
Secondly, in your approach, you lose the initial value of your string, I don't know how important it is.
This is my fast approach using arrray of pointers.
#include <stdio.h>
#include <string.h>
static void print_word(const char *str)
{
for (int i = 0; str[i] && str[i] != ' '; i++)
printf("%c", str[i]);
putchar(' ');
}
int main(void)
{
int len;
const char *str[] = {"This is the first sentence",
"And this is second", NULL};
for (int i = 0; str[i]; i++) {
for (len = strlen(str[i]); len >= 0; len--) {
if (len == 0)
print_word(&str[i][len]);
else if (str[i][len] == ' ')
print_word(&str[i][len + 1]);
}
putchar('\n');
}
printf("Initial value of array of strings [%s | %s] \n", str[0], str[1]);
return 0;
}
output is:
sentence first the is This
second is this And
Initial value of array of strings [This is the first sentence | And this is second]
I suggest you using memcpy but without altering too much your code this seems to work
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_STRING_LENGTH 100
int main()
{
char *str[] = {"This is the first", "And this is the second sentence"};
const size_t NUM_STRING = sizeof(str)/sizeof(char*);
/*%z used to print size_t variables*/
printf("%zd strings found\n", NUM_STRING);
int length[2];
int i;
for (i=0; i<NUM_STRING; i++)
{
length[i] = strlen(str[i]);
}
printf("length initialized %d %d\n", length[0], length[1]);
// Traverse string from end
int j = 0;
char temp[MAX_STRING_LENGTH];
printf("\n\n");
for (j=0; j<NUM_STRING; j++)
{
/*Make sure the string respect the MAX_STRING_LENGTH limit*/
if (strlen(str[j])>MAX_STRING_LENGTH)
{
printf("ERROR: string %d exceding max string length %d defined in constant "
"MAX_STRING_LENGTH. Exiting from program.\n", j, MAX_STRING_LENGTH);
exit(1);
}
//reset temporary string
memset(temp, '\0', sizeof(temp));
//printf("temp variable reinitialized\n");
for (i = length[j] - 1; i >= 0; i--)
{
temp[i] = str[j][i];
if (str[j][i] == ' ')
{
// putting the NULL character at the position of space characters for next iteration.
temp[i] = '\0';
// Start from next character
printf("%s ", &(temp[i]) + 1);
}
}
// printing the last word
printf("%s ", temp);
}
printf("\n");
return 0;
}
The for loop below continues until the end of the string, while the if branch checks to see how many times the character 'u' appears in the string, "yuzuf Oztuk", which is 3 times. Meanwhile, the variable count counts the number of u's in the string. When i compile the code, I get 15 for the number of times u appears in the string, which is wrong.
int numTimesAppears(char* mystring, char ch)
{
int i;
int count;
for(i = 0; mystring[i] != '\0' ; ++i)
{
if (mystring[i] == ch)
{
count++;
}
}
return count;
}
I get 15 for the number of times u appears in the string, which is wrong.
Key issue: Code needs to initialize the value of count. #BLUEPIXY
// int count;
int count = 0;
Corner case: As the null character is in the string, a result of 1 "for number of times a character appears in a string" would be expected for any numTimesAppears(some_string, '\0'). A do loop fixes that. A similar standard library function is strchr(), which looks for the first match and considers the null character part of the search-able string: "... terminating null character is considered to be part of the string." As with all corner cases, various results could be inferred - best to document the coding goal in this case.
i = 0;
do {
if (mystring[i] == ch) {
count++;
}
} while (mystring[i++]);
As the function does not modify the inspected string, making it const increases the function's applicability and perhaps performance. #Vlad from Moscow
Array indexing best uses size_t rather than int. int may be too narrow.
size_t numTimesAppears(const char* mystring, char ch) {
size_t count = 0;
size_t i = 0;
do {
if (mystring[i] == ch) {
count++;
}
} while (mystring[i++]);
return count;
}
void RemoveSpace(char *String)
{
int i=0,y=0;
int leading=0;
for(i=0,y=0;String[i]!='\0';i++,y++)
{
String[y]=String[i]; // let us copy the current character.
if(isspace(String[i])) // Is the current character a space?
{
if(isspace(String[i+1])||String[i+1]=='\0'||leading!=1) // leading space
y--;
}
else
leading=1;
}
String[y]='\0';
}
Does this do the trick of removing leading and trailing whitespaces and replacing multiple whitespaces with single ones ??
i tested it for null string, all whitespaces, leading whitespaces and trailing whitespaces.
Do you think this is an efficient one pass solution ??
Does this do the trick of removing leading and trailing white spaces and replacing multiple white spaces with single ones?
The best way to answer that question is to test it.
void Test(const char *input, const char *expected_output) {
char buffer[80];
strcpy(buffer, input);
RemoveSpace(buffer);
assert(strcmp(buffer, expected_output) == 0);
}
int main() {
Test(" Leading spaces removed.", "Leading spaces removed.");
Test("Trailing spaces removed. ", "Trailing spaces removed.");
Test("Inner spaces trimmed.", "Inner spaces trimmed.");
Test(" A little of everything. ", "A little of everything.");
Test(" \tTabs \t\tare \t spaces, too.", "Tabs are spaces, too.");
return 0;
}
The code in the OP does not pass the last test, so the answer is no.
Do you think this is an efficient one pass solution?
It is a one-pass solution. If you're trying to squeeze every ounce of efficiency out, then you want to minimize the number of operations and conditional branches.
When working with C strings in C, it's often most idiomatic to use pointers rather than indexing. Depending on the compiler and the target platform, using pointers may be more or less efficient than indexing, but both are very low cost. Since this is already a single, linear pass, the best thing to do is to write it as clearly as you can, using idiomatic code patterns.
Here's my solution:
#include <assert.h>
#include <ctype.h>
#include <string.h>
void RemoveSpace(char *string) {
char *target = string;
char *last = target;
int skipping_spaces = 1;
for (const char *source = string; *source != '\0'; ++source) {
if (isspace(*source)) {
if (!skipping_spaces) {
*target++ = *source;
skipping_spaces = 1;
}
} else {
*target++ = *source;
last = target;
skipping_spaces = 0;
}
}
*last = '\0';
}
It's essentially a little state machine, which means that, at each step, we decide what to do based on the current input character and the current state. For this problem, our state is simply whether or not we're currently skipping spaces (and a bookmark keeping track of the last legal point to end the string).
Following code should do it :
void rem_space(char *str)
{
int len = strlen(str) - 1;
int i = 0;
int spaces = 0;
if(str == NULL) return;
while(i < len){
while(str[i] == ' ') {spaces++; i++;}
while(str[i] != ' ' && str[i] != '\0') {str[i - spaces] = str[i]; i++;}
if(str[i + spaces - 1] != '\0') {
str[i - spaces] = ' '; spaces--;
} else {
break;
}
}
str[i - spaces] = '\0';
return;
}
based on your code, assume your iswhite() is efficient,
(which you might not make it separate, as it is called too frequent)
assume the passed in string is valid itself (should be more defensive)
=======================
void RemoveSpace(char *String)
{
int i=0, j=0;
int inWhite=0;
char c = String[i++];
while(c)
{
if (isspace(c))
{
inWhite= 1;
}
else
{
// there are space before, and not beginning
if (inWhite && j > 0)
{
String[j++] = ' ';
}
String[j++] = c;
inWhite = 0;
}
c = String[i++];
}
String[j]='\0';
}
not tested, please test yourself...
First of, obviously, it's one-pass. However, it has a problem when input has more than one leading spaces. For example:
Input: " text" Output: " text"
Fortunately, it's easy to fix it. You just need an extra loop:
void RemoveSpace(char *string)
{
int i = 0, y = 0;
while(isspace(string[i])) // Discard leading spaces.
i++;
for(y = 0; string[i]!='\0'; i++)
{
string[y] = string[i]; // let us copy the current character.
if(!isspace(string[i]) || !isspace(string[i+1]) && !string[i+1]=='\0')
y++; // This character shall not be covered.
}
string[y] = '\0';
}
I also made some changes to make your code looks better, which are actually irrelevant.
'''
python... 3.x
import operator
...
line: line of text
return " ".join(filter(lambda a: operator.is_not(a, ""), line.strip().split(" ")))
'''