I'm trying to write a program that inputs a string (that is actually a sentence) and an array. The function should check if the values in the array are the lengths of each word in the string.
Example 1:
This is an example. (The array should be: [4,2,2,7].
Example 2:
Space... The final frontier... (The array should be: [5,3,5,8]).
I'm struggling with a few things:
How do I check if the length of a word is equal to the value in the array without putting the lengths in another array?
Why does my code register symbols like ('.','!'...) as words?
Why is my lengthofstring always 0? Is my if-statement wrong?
Here is what I have written so far.
int checklength(const char *str,int array[],int n)
{
int i,j=0,start=0,end,lengthofword,lengthofstring,isittrue=0;
while(*(str+lengthofstring)!='\0')
{
lengthofstring++;
}
for(i=0;i<lengthofstring+1;i++)
{
if((*(str+i)>=32 && *(str+i)<=64) || (*(str+i)>=91 && *(str+i)<=96) || (*(str+i)>=123 && *(str+i)<=126))
{
end=i;
lengthofword=end-start; //Why is my lengthofword 0 here?
//Here is what I tried for checking if value is in array:
j++;
while(j<n)
{
if(array[j]==lengthofword)
{
isittrue=1;
}
break;
}
}
start=i+1;
}
return isittrue;
}
You check one word at a time and exit when the first length test fails.
*(str+i)>=32 && *(str+i)<=64) matches those symbols and you don't exclude it elsewhere.
You operate on uninitialized data which is undefined behavior.
Here is how I would write this:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int is_word_len(const char *str, size_t n) {
size_t i = 0;
for(; i < n; i++)
if(!isalpha(str[i]))
return 0;
return !isalpha(str[i]);
}
int is_str_lens(const char *str, size_t n, size_t array[n]) {
// Consider adding checks along these lines:
// assert(str);
// assert(*str);
// assert(n);
// assert(array);
size_t offset = 0;
size_t i = 0;
for(; str[offset] && i < n; i++) {
while(str[offset] && !isalpha(str[offset])) offset++;
if(!is_word_len(&str[offset], array[i]))
return 0;
offset += array[i];
}
while(str[offset] && !isalpha(str[offset])) offset++;
return i == n && !str[offset];
}
int main() {
struct {
char *str;
size_t n;
size_t *array;
} tests[] = {
{ "This is an example.", 4, (size_t []) { 4, 2, 2, 7} },
{ "Space... The final frontier...", 4, (size_t []) { 5, 3, 5, 8 } },
{ "...Space... The final frontier...", 4, (size_t []) { 5, 3, 5, 8 } },
{ "Space...", 2, (size_t []) { 5, 2 } },
{ "Babies x", 1, (size_t []) { 6 } }
{ "This", 2, (size_t []) { 2, 2 } }
};
for(size_t i = 0; i < sizeof tests / sizeof *tests; i++) {
printf("%s: %d\n", tests[i].str, is_str_lens(tests[i].str, tests[i].n, tests[i].array));
}
}
and output:
This is an example.: 1
Space... The final frontier...: 1
...Space... The final frontier...: 1
Space...: 0
Babies x: 0
This: 0
If you don't want to use isalpha() then re-implement along these lines:
int my_isalpha(int c) {
return
c >= 'A' && c <= 'Z' ||
c >= 'a' && c <= 'z';
}
Your code is hard to read and too complicated. You have very handy standard functions which can help you with your task.
int checklength(const char *str, const size_t *array, const size_t n, const char *delim)
{
int isittrue = 1;
size_t cpos = 0;
char *token;
char *modifStr = malloc(strlen(str) + 1);
if(modifStr)
{
strcpy(modifStr, str);
token = strtok(modifStr, delim);
while(token)
{
if(array[cpos] != strlen(token))
{
isittrue = 0;
break;
}
cpos++;
token = strtok(NULL, delim);
}
}
else return -1;
free(modifStr);
return isittrue && cpos == n;
}
int main(void)
{
printf("%d\n", checklength("This is an example.", (size_t[]){4,2,2,7}, 4, " ."));
printf("%d\n", checklength("Space... The final frontier...", (size_t[]){5,3,5,8}, 4, " ."));
}
https://godbolt.org/z/xnf6sK1cx
You can improve this function by adding parameter checks, checking if number of words is not larger than the number of elements of the array etc. But I have left it for you....
I had great trouble following OP's code and so offer a simplification.
Walk the array once. No need for a prior strlen().
Look for word beginnings by noting the transition from non-word to word.
Once in a word, find its end. The one-past-end minus start is the word length.
Use isalpha() to test if a character is a letter. Best to use unsigned characters.
#include <ctype.h>
#include <stdbool.h>
int checklength(const char *str, int array[], int n) {
const unsigned char *s = (const unsigned char*) str;
int i = 0;
while (*str) {
unsigned char ch = *s;
if (isalpha(ch)) {
if (i >= n) {
return true; // no more words to test
}
// Beginning of a word
const unsigned char *next = s + 1;
while (isalpha(*next)) {
next++;
}
// next now points 1 past the end of the word.
// Test word length.
if (next - s != array[i]) {
return false; // Word length does not match
}
i++;
s = next;
} else {
s++;
}
}
return true; // All words match
}
Related
I'm working on a string formatting problem where I'm trying to display the string to the specified size. I need to split the string after 4 commas and display the string in the next line.
INPUT:
char *str = "0-2025,0-2024,0-2023,0-2022,0-2021,0-2020,0-2019,0-2018,0-2017,0-2016";
EXPECTED OUTPUT:
0-2025,0-2024,0-2023,0-2022
0-2021,0-2020,0-2019,0-2018
0-2017,0-2016
I'm trying to add a special character '*' so that I can tokenize and use if for display.
My approach and code is given below, but I'm facing some issue when special character is added at the end.
#include <stdio.h>
#include <string.h>
int nthChar(char *str, char ch, int N){
int occur = 0;
for (int i = 0; i < strlen(str); i++) {
if (str[i] == ch) {
occur += 1;
}
if (occur == N)
return i;
}
}
int main()
{
char *str = "0-2025,0-2024,0-2023,0-2022,0-2021,0-2020,0-2019,0-2018,0-2017,0-2016,0-2015,0-2014,0-2013,0-2012,0-2011,0-2010";
char ch = ',';
int N = 4, res;
res = nthChar(str,ch,N);
printf("%d\n", res);
char priority[128];
strcpy(priority,str);
int size=strlen(str);
printf("size = %d\n",size);
int d = size/res;
printf("DIV =%d\n",d);
printf("%s\n", priority);
for(int i=0;i<strlen(str)&&res<strlen(str);i++){
for(int j=1,k=0;j<=d,k<d;j++,k++){
priority[res*j+k] = '*';
}
}
printf("%s", priority);
return 0;
}
Current Output :
27
size = 111
DIV =4
0-2025,0-2024,0-2023,0-2022,0-2021,0-2020,0-2019,0-2018,0-2017,0-2016,0-2015,0-2014,0-2013,0-2012,0-2011,0-2010
0-2025,0-2024,0-2023,0-2022*0-2021,0-2020,0-2019,0-2018*0-2017,0-2016,0-2015,0-2014*0-2013,0-2012,0-2011,0-2010*�O?��
you can create a function which will split with comma and then slice from 0 index to 4 index. With this you can create a div and append them anywhere. Here is the code:
const comaSplit = () => {
const text = document.getElementById('main').innerText
const array = text.split(',')
let init = 0
for (i = 0; i < array.length; i += 4) {
const first = array.slice(init, (init + 4))
const string = first.join(',')
init = init + 4
const div = document.createElement('div')
div.innerText = string
document.getElementById('root').appendChild(div)
}
}
comaSplit()
#include <stdio.h>
#include <string.h>
int nthChar(char *str, char ch, int N){
int occur = 0;
for (int i = 0; i < strlen(str); i++) {
if (str[i] == ch) {
occur += 1;
}
if (occur == N)
return i;
}
}
int main()
{
char *str = "0-2025,0-2024,0-2023,0-2022,0-2021,0-2020,0-2019,0-2018,0-2017,0-2016,0-2015,0-2014,0-2013,0-2012,0-2011,0-2010";
char ch = ',';
int N = 4, res;
res = nthChar(str,ch,N);
char priority[128];
strcpy(priority,str);
int size=strlen(str);
//printf("size = %d\n",size);
int d = size/res;
//printf("DIV =%d\n",d);
//printf("%s\n", priority);
for(int j=1,k=0;j<=d,k<d && res<strlen(str);j++,k++){
if((res*j+k)==size){
//printf("End of the string check\n");
priority[res*j+k] = '\0';
}else {
//printf("index =%d\n",(res*j+k));
priority[res*j+k] = '*';
}
}
char* token = strtok(priority, "*");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, "*");
}
return 0;
}
OUTPUT:
0-2025,0-2024,0-2023,0-2022
0-2021,0-2020,0-2019,0-2018
0-2017,0-2016,0-2015,0-2014
0-2013,0-2012,0-2011,0-2010
I've tried an approach to find nth comma and then replace that with a distinct special character to tokenize it later for display purpose.
By reading blogs and more about char array I understood that the last character of the string should be '\0' which is by default handled.
I've tried a approach of changing every 4th comma to a special character and then tokenizing with that to display the output.
I have a char array containing a number.
char number[] = "12000000"
I need to have a function to insert a divider in every 3 digits. Like:
char result[] = "12,000,000"
My function accepts the number as a char pointer and it needs to return result as a char pointer too.
char* insert_divider(char* number) {
some magic;
return result;
}
I have no idea of working with pointers. Thanks.
Here you have a function that adds char c every num characters starting from the end. You need to make sure that the string buffer is long enough to accommodate the amended string.
char *addEvery(char *str, char c, unsigned num)
{
char *end = str;
if(str && *str && num)
{
size_t count = 1;
while(*(end)) end++;
while(end != str)
{
end--;
count++;
if(!(count % (num + 1)) && str != end)
{
memmove(end + 1, end, count);
*end = c;
count++;
}
}
}
return str;
}
int main(void)
{
char str[100] = "120000000000";
printf("%s", addEvery(str,',',3));
}
I came up with this piece of code:
char *result;
result = (char*) malloc(15);
int len= strlen(input);
uint8_t cursor= 0;
for(int i = 0; i < len; i++) {
if ((len- i) > 0 && (len- i) % 3 == 0) {
result[i + cursor] = ',';
cursor++;
}
result[i + cursor] = input[i];
}
result[len+ cursor] = '\0';
Thanks everyone for help and advice.
Here is another way to do it:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* insert_divider(char* number, size_t length) {
int j = length + length/3; // every 3 digits a ',' will be inserted
char *out = (char*)malloc(j + 1);
out[j--] = '\0';
for (int i = length - 1, k = 1; i >= 0; i--, k++) {
out[j--] = number[i];
if ((k%3) == 0) {
out[j--] = ',';
}
}
return out;
}
int main(){
char number[] = "12000000";
char *outNumber = insert_divider(number, strlen(number));
printf("%s", outNumber);
free(outNumber);
return 0;
}
Given an array of character strings such as...
char *example[] = {"s", "ss", "sss"};
How can I write a function to count the total number of chars in the array including the terminating characters, without using the standard library for strlen() etc.
Follows is my attempt
int countChars(char *array[], int len)
{
int total = 0, count = 0;
for (int i = 0; i < len; i++)
{
if (array[i] != NULL)
{
while (*array[i] != '\0') {
count++;
}
count++;
}
total += count;
}
return total;
}
An explanation on how char *array[] actually works for access wold be appreciated. I believe that it is supposed to be an array of pointers to strings.
You have to increment the index to consider each of the character.
Something like this:-
for (int i = 0; i < len; i++)
{
if (array[i] != NULL)
{
int j=0,count=0;
while (array[i][j++] != '\0') {
count++;
}
total += count;
}
}
Also reset the count or add to total at the end of all the calculation.
As an answer to your second question:-
char* array[] is basically denoting an array pointers each pointing
to the string literals with which you initialized it.
So once you use array[i] you should now think that it is nothing
other than a pointer to a string literal.
You need to reinitialize the variable count inside the for loop for each processed string and to increase the expression *array[i] inside the while loop.
Also it is better when the function has the return type size_t (size_t is the type that is returned by the standard C function strlen and by the operator sizeof)
The function can look as it is shown in the demonstrative program.
#include <stdio.h>
size_t countChars( const char *array[], size_t n )
{
size_t count = 0;
while ( n-- )
{
if ( array[n] )
{
size_t i = 0;
do { ++count; } while ( array[n][i++] );
}
}
return count;
}
int main(void)
{
const char * example[] = { "s", "ss", "sss" };
printf( "%zu\n", countChars( example, sizeof( example ) / sizeof( *example ) ) );
return 0;
}
The program output is
9
Each element of this array
char *example[] = {"s", "ss", "sss"};
has type char * and is a pointer to the first character of the corresponding string literal.
Since your array contains string constants you should declare it with const:
const char *example[3];
Without const the compiler will not warn you if you try to assign a character to example[i][j]. For the same reason the formal parameter should also be declared with const.
For a pure function with no side effects it is better to name it so that it reflects the result. Therefor I would use charCount instead of countChars (or maybe totalLength). The focus should be on a noun (namely count or length).
Here is my solution:
#include <stdio.h>
#define LEN(a) (sizeof (a) / sizeof (a)[0])
static int CharCount(const char *strings[], int len)
{
int result, i, j;
result = 0;
for (i = 0; i < len; i++) {
j = 0;
while (strings[i][j] != '\0') {
result++;
j++;
}
}
return result;
}
int main(void)
{
const char *strings[] = { "s", "ss", "sss" };
printf("character count: %d\n", CharCount(strings, LEN(strings)));
}
The length macro LEN is very convenient and is the least error prone way to handle array lengths.
Yes char *array[] = {"aa", "bb", "cc"} is an array of pointers to strings.
array[0] points to "aa"
array[1] points to "bb"
array[2] points to "cc"
You probably want this:
int countChars(char *array[], int len)
{
int count = 0;
for (int arrayindex = 0; arrayindex < len; arrayindex++)
{
const char *stringptr = array[arrayindex];
// stringptr will point successively
// to "s", to "ss" and to "sss"
while (*stringptr++)
count++; // increment count until NUL character encountered
count++; // one more for NUL character
}
return count;
}
int main() {
char *example[] = { "s", "ss", "sss" };
int x = countChars(example, 3); // x contains 9 after the call to countChars
// that is 2 + 3 + 4
}
Instead of hard coding 3 you could use sizeof(example) / sizeof(example[0]).
I have to find the count of a substring in a string using the C language.
I'm using the function strstr but it only finds the first occurrence.
My idea of the algorithm is something like searching in the string while strstr does not return null and
to substring the main string on each loop.
My question is how to do that?
You could do something like
int countString(const char *haystack, const char *needle){
int count = 0;
const char *tmp = haystack;
while(tmp = strstr(tmp, needle))
{
count++;
tmp++;
}
return count;
}
That is, when you get a result, start searching again at the next position of the string.
strstr() doesn't only work starting from the beginning of a string but from any position.
Should already processed parts of the string should be consumed or not?
For example, what's the expect answer for case of searching oo in foooo, 2 or 3?
If the latter (we allow substring overlapping, and the answer is three), then Joachim Isaksson suggested the right code.
If we search for distinct substrings (the answer should be two), then see the code below (and online example here):
char *str = "This is a simple string";
char *what = "is";
int what_len = strlen(what);
int count = 0;
char *where = str;
if (what_len)
while ((where = strstr(where, what))) {
where += what_len;
count++;
}
USE KMP and you can do it in O(n)
int fail[LEN+1];
char s[LEN];
void getfail()
{
//f[i+1]= max({j|s[i-j+1,i]=s[0,j-1],j!=i+1})
//the correctness can be proved by induction
for(int i=0,j=fail[0]=-1;s[i];i++)
{
while(j>=0&&s[j]!=s[i]) j=fail[j];
fail[i+1]=++j;
if (s[i+1]==s[fail[i+1]]) fail[i+1]=fail[fail[i+1]];//optimizing fail[]
}
}
int kmp(char *t)// String s is pattern and String t is text!
{
int cnt=0;
for(int i=0,j=0;t.s[i];i++)
{
while(j>=0&&t.s[i]!=s[j]) j=fail[j];
if (!s[++j])
{
j=fail[j];
cnt++;
}
}
return cnt;// how many times s appeared in t.
}
The results can be different depending whether you allow an overlap or not:
// gcc -std=c99
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
static int
count_substr(const char *str, const char* substr, bool overlap) {
if (strlen(substr) == 0) return -1; // forbid empty substr
int count = 0;
int increment = overlap ? 1 : strlen(substr);
for (char* s = (char*)str; (s = strstr(s, substr)); s += increment)
++count;
return count;
}
int main() {
char *substrs[] = {"a", "aa", "aaa", "b", "", NULL };
for (char** s = substrs; *s != NULL; ++s)
printf("'%s' -> %d, no overlap: %d\n", *s, count_substr("aaaaa", *s, true),
count_substr("aaaaa", *s, false));
}
Output
'a' -> 5, no overlap: 5
'aa' -> 4, no overlap: 2
'aaa' -> 3, no overlap: 1
'b' -> 0, no overlap: 0
'' -> -1, no overlap: -1
Assuming s and substr are non-null and non-empty:
/* #times substr appears in s, no overlaps */
int nappear(const char *s, const char *substr)
{
int n = 0;
const char *p = s;
size_t lenSubstr = strlen(substr);
while (*p) {
if (memcmp(p, substr, lenSubstr) == 0) {
++n;
p += lenSubstr;
} else
++p;
}
return n;
}
/*
* C Program To Count the Occurence of a Substring in String
*/
#include <stdio.h>
#include <string.h>
char str[100], sub[100];
int count = 0, count1 = 0;
void main()
{
int i, j, l, l1, l2;
printf("\nEnter a string : ");
scanf("%[^\n]s", str);
l1 = strlen(str);
printf("\nEnter a substring : ");
scanf(" %[^\n]s", sub);
l2 = strlen(sub);
for (i = 0; i < l1;)
{
j = 0;
count = 0;
while ((str[i] == sub[j]))
{
count++;
i++;
j++;
}
if (count == l2)
{
count1++;
count = 0;
}
else
i++;
}
printf("%s occurs %d times in %s", sub, count1, str);
}
The definition of library function strspn is:
size_t strspn(const char *str, const char *chars)
/* Return number of leading characters at the beginning of the string `str`
which are all members of string `chars`. */
e.g. if str is "fecxdy" and chars is "abcdef" then the function would return 3, since f, e and c all appear somewhere in chars, giving 3 leading characters of str, and x is the first character of str which is not a member of chars.
Could someone help me write an implementation of strspn in C. The only library function I am allowed to call from the implementation is strlen?
The basic idea is to step through the string, one character at a time, and test if it's in the character set. If it's not, stop and return the answer. In pseudocode, that would look like:
count = 0
for each character c in str
if c is not in chars
break
count++
return count
The if c is not in chars test can be implemented by iterating through all of the characters of chars and testing if c matches any of the characters. Note that this is not the fastest implementation, since it involves stepping through the chars string for each character in str. A faster implementation would use a lookup table to test if c is not in chars.
I found this question while going over old exams. You weren't allowed to use indexing or any standard functions. Here's my attempt at a solution:
#include <stdio.h>
size_t myStrspn(const char *str1, const char *str2){
size_t i,j;
i=0;
while(*(str1+i)){
j=0;
while(*(str2+j)){
if(*(str1+i) == *(str2+j)){
break; //Found a match.
}
j++;
}
if(!*(str2+j)){
return i; //No match found.
}
i++;
}
return i;
}
void main(){
char s[] = "7803 Elm St.";
int n = 0;
n = myStrspn(s,"1234567890");
printf("The number length is %d. \n",n);
}
Here's the solution from the exam:
#include<stdio.h>
size_t strspn(const char* cs, const char* ct) {
size_t n;
const char* p;
for(n=0; *cs; cs++, n++) {
for(p=ct; *p && *p != *cs; p++)
;
if (!*p)
break;
}
return n;
}
For loops made it much more compact.
I think this should be pretty fast
size_t strspn(const unsigned char *str, const unsigned char *chars){
unsigned char ta[32]={0};
size_t i;
for(i=0;chars[i];++i)
ta[chars[i]>>3]|=0x1<<(chars[i]%8);
for(i=0;((ta[str[i]>>3]>>(str[i]%8))&0x1);++i);
return i;
}
Thanks to others for sanity checks.
A naive implementation of strspn() would iterate on the first string, as long as it finds the corresponding character in the second string:
#include <string.h>
size_t strspn(const char *str, const char *chars) {
size_t i = 0;
while (str[i] && strchr(chars, str[i]))
i++;
return i;
}
Given that you are not allowed to call strchr(), here is a naive native implementation:
size_t strspn(const char *str, const char *chars) {
size_t i, j;
for (i = 0; str[i] != '\0'; i++) {
for (j = 0; chars[j] != str[i]; j++) {
if (chars[j] == '\0')
return i; // char not found, return index so far
}
}
return i; // complete string matches, return length
}
Scanning the second string repeatedly can be costly. Here is an alternative that combines different methods depending on the length of chars, assuming 8-bit bytes:
size_t strspn(const char *str, const char *chars) {
size_t i = 0;
char c = chars[0];
if (c != '\0') { // if second string is empty, return 0
if (chars[1] == '\0') {
// second string has single char, use a simple loop
while (str[i] == c)
i++;
} else {
// second string has more characters, construct a bitmap
unsigned char x, bits[256 / 8] = { 0 };
for (i = 0; (x = chars[i]) != '\0'; i++)
bits[x >> 3] |= 1 << (x & 7);
// iterate while characters are found in the bitmap
for (i = 0; (x = str[i]), (bits[x >> 3] & (1 << (x & 7))); i++)
continue;
}
}
return i;
}
int my_strspn(const char *str1,const char *str2){
int i,k,counter=0;
for(i=0;str1[i]!='\0';i++){
if(counter != i) break;
for(k=0;str2[k]!='\0';k++){
if(str1[i]==str2[k])
counter++;
}
}
return counter;
}
Create a lookup table (a poor man's set) for all possible ASCII chars, and just lookup each character in str. This is worst case O(max(N,M)), where N is the number of characters in str and M is the number of characters in chars.
#include <string.h>
size_t strspn(const char *str, const char *chars) {
int i;
char ch[256] = {0};
for (i = 0; i < strlen(chars); i++) {
ch[chars[i]] = 1;
}
for (i = 0; i < strlen(str); i++) {
if (ch[str[i]] == 0) {
break;
}
}
return i;
}
This could also be solved without using strlen at all, assuming both strings are zero-terminated. The disadvantage of this solution is that one needs 256 bytes of memory for the lookup table.
Without touching a C-compiler for the last couple of years. From the top of my head something like this should work:
int spn = 0;
while(*str++ != '\0')
{
char *hay = chars;
bool match = false;
while(*hay++ != '\0')
{
if(*hay == *str)
{
match = true;
break;
}
}
if(match)
spn++;
else
return spn;
}
return spn;
Well, implementing a standard library for my OS, here is my solution (C++).
KCSTDLIB_API_FUNC(size_t DECL_CALL strspn(const char * str1, const char * str2))
{
size_t count = 0;
auto isin = [&](char c)
{
for (size_t x = 0; str2[x]; x++)
{
if (c == str2[x])
return true;
};
return false;
};
for (; isin(str1[count]); count++);
return count;
}