Splitting an array without an inbuilt function - c

The code below is meant to take an input string like My name is Smith and outputs
My
name
is
Smith
and also has to exclude things like: , . and space, just these three, but instead it outputs, I'm not allowed to use any thing like strlen or strtok
My
y
name
ame
me
e
is
s
Smith
mith
ith
th
h
I've searched for the error everywhere in the code and I can't seem to figure it out
int main()
{
int wordSize = 0;
char str[81];
char* ptr_to_word[81];
gets_s(str);
for (char* res_p = &(str[0]); *res_p != '\0'; res_p++) {
if ((*res_p != '.') || (*res_p != ',') || (*res_p != ' '))
{
ptr_to_word[wordSize] = res_p;
wordSize++;
}
}
if (wordSize == 0)
{
printf("no solution");
}
else
{
for (int i = 0; i < wordSize; i)
{
char* a = ptr_to_word[i];
while ((*a != '.') && (*a != ',') && (*a != ' ') && (*a != '\0'))
{
printf("%c", *a);
a++;
}
printf("\n");
}
}
return 0;
}

In the condition of the if statement within this loop
for (char* res_p = &(str[0]); *res_p != '\0'; res_p++) {
if ((*res_p != '.') || (*res_p != ',') || (*res_p != ' '))
{
ptr_to_word[wordSize] = res_p;
wordSize++;
}
}
you have to use the logical AND operator instead of the logical OR operator like
if ((*res_p != '.') && (*res_p != ',') && (*res_p != ' '))
Nevertheless the loop in any case is wrong because the variable wordSize does not count words but counts each character that is not equal to the characters listed in the if statement.
To output separate words there is no need to declare an array of pointers to starts of words. You can output each word as soon as its start is found.
Here is a very simple demonstrative program.
#include <stdio.h>
int main(void)
{
enum { N = 81 };
char s[N];
fgets( s, N, stdin );
for ( const char *p = s; *p; )
{
int wordSize = 0;
while ( *p && *p != '.' && *p != ',' && *p != ' ' && *p != '\t' && *p != '\n' )
{
++wordSize;
++p;
}
if ( wordSize )
{
printf( "%.*s\n", wordSize, p - wordSize );
}
else
{
++p;
}
}
return 0;
}
If to input "My name is Smith" then the program output might look like
My
name
is
Smith
I appended the list of delimiters with the tab character '\t' and the new line character '\n' that can be inserted in the input string by the function fgets.

First of all, this condition
if ((*res_p != '.') || (*res_p != ',') || (*res_p != ' ')
will always be true, think about it, *res_p is always not '.' OR not ','. However, if you change the operator to && your code will still produce the same result.
The first loop with || operator writes a pointer to every character in your input string to the array ptr_to_word, and ' 's and '.'s are not printed only because of a condition in the second loop.
If you change the operator to && like so,
if ((*res_p != '.') && (*res_p != ',') && (*res_p != ' ')
you will write all the pointers, except for the '.', ',' and ' ', into the array, e.g. ptr_to_word[0] will point to 'My name is Smith', ptr_to_word[1] to 'y name is Smith', etc.
I have made a few changes to your code so that it would work as intended.
void split_str(char *str)
{
int wordSize = 0;
char *ptr_to_word[81];
char *res_p = &(str[0]);
int i = 0;
for (; *res_p != '\0'; res_p++) {
if ((*res_p != '.') && (*res_p != ',') && (*res_p != ' '))
{
wordSize++;
}
else
{
ptr_to_word[i] = res_p - wordSize;
wordSize = 0;
i++;
}
}
ptr_to_word[i] = res_p - wordSize;
ptr_to_word[i + 1] = NULL;
if (i == 0)
{
printf("no solution\n");
}
else
{
for (int i = 0; ptr_to_word[i]; i++)
{
char* a = ptr_to_word[i];
while ((*a != '.') && (*a != ',') && (*a != ' ') && (*a != '\0'))
{
printf("%c", *a);
a++;
}
printf("\n");
}
}
}
int main() {
split_str("My name is Smith\n");
}
This way you are writing a new value to the pointer array only when dot, comma or a space is encountered. For all other chars, you just do wordSize++ to keep track of the length of the word. I used pointer arithmetic to move back to the start of the word (ptr_to_word[i] = res_p - wordSize;).
I have tried to make only minimal changes to your code, just enough to make it work. There are still things I would change to make it better, e.g. the first loop finishes when the '\0' is encountered. Most likely, the last word finishes with a '\0', not a '.' or a ' '. Thus, it won't be written to the ptr_to_word, and I had to manually write it after the loop. Also, you don't even need two loops, you can use the same pointer. arithmetic to output the word as soon as it is found. So I'd advise you to do. a self-code-review, and optimize it further.
Good luck!

Related

I get weird symbols in the output in the terminal

I am trying to make a program that would take a sentence from the user and reverse the order of the words while keeping the special characters ['.','?','!'] at the end.
the problem I'm getting is that I get weird symbols after the last word and the special character.
I am programming using C.
I think it's because the last element printed is not a '\0'.
but I don't know how to fix that.
My code:
#include <ctype.h>
#define N 200
int main()
{
char arr[N] = { 0 };
char* p, * q, mark = 0;
int c;
p = arr;
printf("Enter a sentence: ");
while ((c = getchar()) != '\n' && p < arr + N)
{
if (c == '?' || c == '.' || c == '!')
{
mark = c;
break;
}
else
*p++ = c;
}
*p = '\0';
printf("Reversal of sentence: ");
while (p >= arr)
{
while (*--p != ' ' && p != arr);
if (p == arr) {q = arr;}
else {q = p + 1;}
while (*q != '\0' && *q != ' ')
{
printf("%c", *q++);
}
if (p >= arr)
{
printf(" ");
}
}
printf("%c", mark);
printf("\n");
return 0;
}
I've fixed the overflow error when reading the sentence by removing the \0 termination. The input string is never used by anything that cares. I've also added a check for End-Of-File.
Next I changed the reversal loop to not underflow and fixed outputing an extra ' ' before the mark.
Last the printf calls can use putchar instead.
#include <ctype.h>
#include <stdio.h>
#define N 200
int main()
{
char arr[N] = { 0 }; // initialization optional, nothing cares
char* p, * q, mark = 0;
int c;
p = arr;
printf("Enter a sentence: ");
while ((c = getchar()) != '\n' && c != EOF && p < arr + N)
{
if (c == '?' || c == '.' || c == '!')
{
mark = c;
break;
}
else
*p++ = c;
}
printf("Reversal of sentence: ");
while (p > arr)
{
while (*--p != ' ' && p != arr);
if (p == arr) {q = arr;}
else {q = p + 1;}
while (*q != '\0' && *q != ' ')
{
putchar(*q++);
}
if (p > arr)
{
putchar(' ');
}
}
putchar(mark);
putchar('\n');
return 0;
}

Problem in building a function that counts the letters in a function - Cs50

I am getting an int of the entire string s for 'letter', the conditions in my 'if' statement seem to not be reading properly - is my syntax incorrect?
I get user input:
string s = get_string("Text here: ");
the function is as follows:
int letter_count(string s)
{
int i =0;
int len = strlen(s);
int letter = 0;
while(i < len)
{
if (s[i] != '\0' || s[i] != '.' || s[i] != ',' || s[i] != '!' || s[i] != '?')
{
letter++;
}
i++;
}
return letter;
}
then call the function:
int letter = letter_count(s);
printf("letter Count: %i\n", letter);
Try changing the OR operator with the AND
if (s[i] != '\0' || s[i] != '.' || s[i] != ',' || s[i] != '!' || s[i] != '?')
is ALWAYS true. Because any character is either not "." or not ",". Which letter would you expect to be both?
You want to check whether the current letter is "not ." AND "not ," AND "not !".
I.e.
if (s[i] != '\0' && s[i] != '.' && s[i] != ',' && s[i] != '!' && s[i] != '?')
Almost correct, you have to change the type of the argument to char*, there is no string type on the default libraries. (Documentation of string library).
Working example with the modifications:
#include <stdio.h>
#include <string.h>
int letter_count (char* s)
{
int i = 0;
int len = strlen (s);
int letter = 0;
while (i < len)
{
if (s[i] != '\0' && s[i] != '.' && s[i] != ',' && s[i] != '!'
&& s[i] != '?')
{
letter++;
}
i++;
}
return letter;
}
int main ()
{
char my_word[] = "Sample word";
printf ("'%s' have %d letters",my_word, letter_count (my_word));
return 0;
}
Output:
'Sample word' have 11 letters

counting words of a string

As the title states, few things I must add to explain: " "/tab/","/"." are things that divide words in my situation, another note that there can be more the one space or dot coming one after the other
this is what I have
int countWords(char * str, int length){
int counter = 0;
for( int i = 0; i < length; i++){
if(( str[i] == " ") || ( str[i] == ".") || ( str[i] == ",")){
if(( str[i+1] != " ") || ( str[i+1] != ".") || (str[i+1] != ",")){
if(( str[i-1] != " ") || ( str[i-1] != ".") || (str[i-1] != ","))
counter++;
}
}
}
return counter;
}
I get an error saying that I can not compare int and a pointer, I do understand where that is coming from, but how can I get it to actually work?
Note* I can't use string.h
In expressions like this
str[i] == " "
^^^
you are trying to compare an object of type char with a string literal that is implicitly converted to the type char *.
You have to use a character constant instead of the string literal
str[i] == ' '
^^^
The enclosing if statements do not make sense. For example for i equal to 0 the expression str[i-1] tries to access memory beyond the string.
The first parameter of the function should be declared with qualifier const.
The function can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
size_t countWords( const char *s )
{
size_t n = 0;
for (size_t i = 0; s[i] != '\0'; )
{
while (s[i] == ' ' ||
s[i] == '\t' ||
s[i] == '.' ||
s[i] == ',') ++i;
if (s[i] != '\0')
{
++n;
while ( s[i] != '\0' &&
! ( s[i] == ' ' ||
s[i] == '\t' ||
s[i] == '.' ||
s[i] == ',')) ++i;
}
}
return n;
}
int main( void )
{
char *s = " Hello\t, World...";
printf("%zu\n", countWords(s));
}
The program output is
2
Or the function's implementation can look like
size_t countWords(const char *s)
{
size_t n = 0;
while ( *s )
{
while (*s == ' ' ||
*s == '\t' ||
*s == '.' ||
*s == ',') ++s;
if ( *s )
{
++n;
while ( *s &&
!( *s == ' ' ||
*s == '\t' ||
*s == '.' ||
*s == ',' ) ) ++s;
}
}
return n;
}
A more general approach of declaring the function is the following
size_t countWords( const char *s1, const char *s2 );
where the string s2 specifies a set of word separators.
If you want to count word there is one fine example in K&R ANSI C. Try to write program like this.
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* count lines, words, and characters in input */
main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF)
{
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c = '\t')
state = OUT;
else if (state == OUT)
{
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
Hope this helps. :) You can find the pdf of this book here.

Can't convert lowercase to uppercase with pointer

So I want to make lowercase letters to uppercase with one condition, before the lowercase letter there must be space, but the problem is I can't
check if the next char in the array(using +1) is a space or not.
#include <stdio.h>
#include <ctype.h>
void convertToUpper( char *array );
int main()
{
char x[] = "i believe i can do it";
convertToUpper(x);
printf("%s",x);
return 0;
}
void convertToUpper( char *array )
{
while( *array != '\0' )
{
if( *( array + 1 ) != ' ' && *array == ' ' )
{
*( ++array) = toupper( *(array) );
}
++array;
}
}
You are simply convert the wrong character, because in your condition, *array is space, you should convert the letter after it:
while(*array != '\0')
{
if( *(array + 1) != ' ' && *array == ' ')
*(array + 1) = toupper(*(array + 1));
++array;
}
This simple check won't work for the 1st char, if it should be upper case too, add following before the loop:
if (*array != ' ')
*array = toupper(*array)
void convertToUpper( char *array )
{
while ( array[0] != 0) && (array[1] != 0) )
{
if( (array[1] != ' ') && (array[0] == ' ' )
array[1] = toupper( array[1] );
++array;
}
}
This way remembers the previous character
char previous = ' ';
while(*array != '\0') {
if(previous == ' ') {
*array = toupper(*array);
}
previous = *array++;
}
just after an answer accepted, but I post anyway.

Remove preceding spaces and tabs from a given string in C language

What C function, if any, removes all preceding spaces and tabs from a string?
In C a string is identified by a pointer, such as char *str, or possibly an array. Either way, we can declare our own pointer that will point to the start of the string:
char *c = str;
Then we can make our pointer move past any space-like characters:
while (isspace(*c))
++c;
That will move the pointer forwards until it is not pointing to a space, i.e. after any leading spaces or tabs. This leaves the original string unmodified - we've just changed the location our pointer c is pointing at.
You will need this include to get isspace:
#include <ctype.h>
Or if you are happy to define your own idea of what is a whitespace character, you can just write an expression:
while ((*c == ' ') || (*c == '\t'))
++c;
A simpler function to trim white spaces
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * trim(char * buff);
int main()
{
char buff[] = " \r\n\t abcde \r\t\n ";
char* out = trim(buff);
printf(">>>>%s<<<<\n",out);
}
char * trim(char * buff)
{
//PRECEDING CHARACTERS
int x = 0;
while(1==1)
{
if((*buff == ' ') || (*buff == '\t') || (*buff == '\r') || (*buff == '\n'))
{
x++;
++buff;
}
else
break;
}
printf("PRECEDING spaces : %d\n",x);
//TRAILING CHARACTERS
int y = strlen(buff)-1;
while(1==1)
{
if(buff[y] == ' ' || (buff[y] == '\t') || (buff[y] == '\r') || (buff[y] == '\n'))
{
y--;
}
else
break;
}
y = strlen(buff)-y;
printf("TRAILING spaces : %d\n",y);
buff[strlen(buff)-y+1]='\0';
return buff;
}
void trim(const char* src, char* buff, const unsigned int sizeBuff)
{
if(sizeBuff < 1)
return;
const char* current = src;
unsigned int i = 0;
while(current != '\0' && i < sizeBuff-1)
{
if(*current != ' ' && *current != '\t')
buff[i++] = *current;
++current;
}
buff[i] = '\0';
}
You just need to give buff enough space.
You can setup a counter to count the corresponding number of spaces, and accordingly shift the characters by that many spaces. Complexity for this ends up at O(n).
void removeSpaces(char *str) {
// To keep track of non-space character count
int count = 0;
// Traverse the given string. If current character
// is not space, then place it at index count
for (int i = 0; str[i]; i++)
if (str[i] != ' ')
str[count++] = str[i]; // increment count
str[count] = '\0';
}

Resources