I am trying to copy from one string to another, but the second string should omit the space. I tried to approach this by saying, if a character in the original string is a space, do not copy it. Instead, copy the next character. However, the program deletes everything after the space. Any ideas?
char deleteSpaces(char phrase[256], int length){
int j, i=0;
char phrase2[length];
for(j=0;j<length;j++){
if(phrase[i]==' '){
phrase2[j]=phrase[i+1];
i++;
}
phrase2[j]=phrase[i];
}
return phrase2;
}
Here is a solution:
void deleteSpaces(char src[], char dst[]){
// src is supposed to be zero ended
// dst is supposed to be large enough to hold src
int s, d=0;
for (s=0; src[s] != 0; s++)
if (src[s] != ' ') {
dst[d] = src[s];
d++;
}
dst[d] = 0;
}
First, you're returning a static tab and this is wrong.
Secondly you don't increment 'i' if there is no space.
And to finish you will copy spaces if there is more than one space in a row. And you do not control if you reach the end of your source.
for(j = 0; j < length; j++)
{
while (src[i] == ' ' && i < length) i++;
if (i < length)
dest[j] = src[i++];
else
{
dest[j] = 0;
break;
}
}
My solution. Arguments and their order are chosen to match strncpy().
#include <ctype.h>
char *strip_whitespace(char *dest, const char *src, size_t n)
{
char *s, *d;
/*
* Copy 'src' to 'dest', omitting whitespace and making sure we don't
* overflow 'dest'.
*/
for(s=src, d=dest; *s && (d-dest)<n; s++) {
if( !isspace(*s) ) {
*d = *s;
d++;
}
}
/* Ensure that dest is NUL terminated in any event */
if( d-dest < n ) {
*d = '\0';
} else {
dest[n-1] = '\0';
}
return dest;
}
As pointed out already you need to allocate a new string and return a pointer to it. This code works:
char* strip (char* input)
{
int loop;
char *output = (char*) malloc (strlen(input));
char *dest = output;
if (output)
{
for (loop=0; loop<strlen(input); loop++)
if (input[loop] != ' ')
*dest++ = input[loop];
*dest = '\0';
}
return output;
}
int main (void)
{
char srcString[] = " this is a test with spaces at the end ";
char* dstString = strip (srcString);
printf ("source string = '%s'\n", srcString);
printf (" dest string = '%s'\n", dstString ? dstString : "malloc failed in strip");
free (dstString);
return 0;
}
Output:
source string = ' this is a test with spaces at the end '
dest string = 'thisisatestwithspacesattheend'
It takes the input string and allocates a destination string the same size which is safe, although wasteful of a few bytes.
The method is simple; only copy a character if it is not a space. After all the characters are copied, I write the terminator on the end and return the pointer.
****WHAT YOU WERE DOING** IS THAT if a character in the original string is a space, do not copy it. Instead, copy the next character. IS NOT A GOOD idea because
Case 1. When multiple spaces are present, it simply discard the first spaces and copies the second one...
Case 2: Your programme copies the string only after space is found,,it is simply skipping the first word of string which doesn't start with spaces.
case 3. You are only returning the character pointed by phrase2[0] as return type is char,and the scope of local variable is limited to only that function....
//the corrected programme
int deleteSpaces(char phrase[256],charphrase2[256])
{
int i,j;
i=j=0;
while(phrase[i]!=NULL){
if(phrase[i]!=' '){
phrase2[j]=phrase[i];
j++;
}
i++;
}//end while
phrase2[j]=phrase[i] //nulcharceter copied
return 0;
}//end deleteSpaces function
I use this:
char input[100], foreval[100];
for(i=0;i<strlen(input);i++){
if(isspace(input[i])){
continue;
}
strncat(foreval,&input[i],1);
}
Related
My goal in the code is to parse some sort of input into words regarding all spaces but at the same time use those spaces to signify a change in words. The logic here is that anytime it encounters a space it loops until there is no longer a space character and then when it encounters a word it loops until it encounters a space character or a '\0' and meanwhile puts each character into one index of an array inside arrays in the 2d array. Then before the while loop continues again it indexes to the next array.
I'm almost certain the logic is implemented well enough for it to work but I get this weird output listed below I've had the same problem before when messing with pointers and whatnot but I just can't get this to work no matter what I do. Any ideas as to why I'm genuinely curious about the reason behind why?
#include <stdio.h>
#include <stdlib.h>
void print_mat(char **arry, int y, int x){
for(int i=0;i<y;i++){
for(int j=0;j<x;j++){
printf("%c",arry[i][j]);
}
printf("\n");
}
}
char **parse(char *str)
{
char **parsed=(char**)malloc(sizeof(10*sizeof(char*)));
for(int i=0;i<10;i++){
parsed[i]=(char*)malloc(200*sizeof(char));
}
char **pointer = parsed;
while(*str!='\0'){
if(*str==32)
{
while(*str==32 && *str!='\0'){
str++;
}
}
while(*str!=32 && *str!='\0'){
(*pointer) = (str);
(*pointer)++;
str++;
}
pointer++;
}
return parsed;
}
int main(){
char str[] = "command -par1 -par2 thething";
char**point=parse(str);
print_mat(point,10,200);
return 0;
}
-par1 -par2 thethingUP%�W���U�6o� X%��U�v;,���UP%���cNjW��]A�aW�Ӹto�8so�z�
-par2 thethingUP%�W���U�6o� X%��U�v;,���UP%���cNjW��]A�aW�Ӹto�8so�z�
thethingUP%�W���U�6o� X%��U�v;,���UP%���cNjW��]A�aW�Ӹto�8so�z�
UP%�W���U�6o� X%��U�v;,���UP%���cNjW��]A�aW�Ӹto�8so�z�
I also tried to simply index the 2d array but to no avail
char **parse(char *str)
{
int i, j;
i=0;
j=0;
char **parsed=(char**)malloc(sizeof(10*sizeof(char*)));
for(int i=0;i<10;i++){
parsed[i]=(char*)malloc(200*sizeof(char));
}
while(*str!='\0'){
i=0;
if(*str==32)
{
while(*str==32 && *str!='\0'){
str++;
}
}
while(*str!=32 && *str!='\0'){
parsed[j][i] = (*str);
i++;
str++;
}
j++;
}
return parsed;
}
Output:
command�&�v�U`'�v�U0(�v�U)�v�U�)�v�U
-par1
-par2
thething
makefile:5: recipe for target 'build' failed
make: *** [build] Segmentation fault (core dumped)
A couple of problems in your code:
Your program is leaking memory.
Your program is accessing memory which it does not own and this is UB.
Lets discuss them one by one -
First problem - Memory leak:
Check this part of parse() function:
while(*str!=32 && *str!='\0'){
(*pointer) = (str);
In the first iteration of outer while loop, the *pointer will give you first member of parsed array i.e. parsed[0], which is a pointer to char. Note that you are dynamically allocating memory to parsed[0], parsed[1]... parsed[9] pointers in parse() before the outer while loop. In the inner while loop you are pointing them to str. Hence, they will loose the dynamically allocated memory reference and leading to memory leak.
Second problem - Accessing memory which it does not own:
As stated above that the pointers parsed[0], parsed[1] etc. will point to whatever was the current value of str in the inner while loop of parse() function. That means, the pointers parsed[0], parsed[1] etc. will point to some element of array str (defined in main()). In the print_mat() function, you are passing 200 and accessing every pointer of array arry from 0 to 199 index. Since, the arry pointers are pointing to str array whose size is 29, that means, your program is accessing memory (array) beyond its size which is UB.
Lets fix these problem in your code without making much of changes:
For memory leak:
Instead of pointing the pointers to str, assign characters of str to the allocated memory, like this:
int i = 0;
while(*str!=32 && *str!='\0'){
(*pointer)[i++] = (*str);
str++;
}
For accessing memory which it does not own:
A point that you should remember:
In C, strings are actually one-dimensional array of characters terminated by a null character \0.
First of all, empty the strings after dynamically allocating memory to them so that you can identify the unused pointers while printing them:
for(int i=0;i<10;i++){
parsed[i]=(char*)malloc(200*sizeof(char));
parsed[i][0] = '\0';
}
Terminate all string in with null terminator character after writing word to parsed array pointers:
int i = 0;
while(*str!=32 && *str!='\0'){
(*pointer)[i++] = (*str);
str++;
}
// Add null terminator
(*pointer)[i] = '\0';
In the print_mat(), make sure once you hit the null terminator character, don't read beyond it. Modify the condition of inner for loop:
for(int j = 0; (j < x) && (arry[i][j] != '\0'); j++){
printf("%c",arry[i][j]);
You don't need to print the strings character by character, you can simply use %s format specifier to print a string, like this -
for (int i = 0;i < y; i++) {
if (arry[i][0] != '\0') {
printf ("%s\n", arry[i]);
}
}
With the above suggested changes (which are the minimal changes required in your program to work it properly), your code will look like this:
#include <stdio.h>
#include <stdlib.h>
void print_mat (char **arry, int y) {
for (int i = 0; i < y; i++) {
if (arry[i][0] != '\0') {
printf ("%s\n", arry[i]);
}
}
}
char **parse(char *str) {
char **parsed = (char**)malloc(sizeof(10*sizeof(char*)));
// check malloc return
for(int i = 0; i < 10; i++){
parsed[i] = (char*)malloc(200*sizeof(char));
// check malloc return
parsed[i][0] = '\0';
}
char **pointer = parsed;
while (*str != '\0') {
if(*str == 32) {
while(*str==32 && *str!='\0') {
str++;
}
}
int i = 0;
while (*str != 32 && *str != '\0') {
(*pointer)[i++] = (*str);
str++;
}
(*pointer)[i] = '\0';
pointer++;
}
return parsed;
}
int main (void) {
char str[] = "command -par1 -par2 thething";
char **point = parse(str);
print_mat (point, 10);
// free the dynamically allocate memory
return 0;
}
Output:
command
-par1
-par2
thething
There is a lot improvements can be done in your code implementation, for e.g. -
As I have shown above, you can use %s format specifier instead of printing string character by character etc.. I am leaving it up to you to identify those changes and modify your program.
Allocate memory to a parsed array pointer only where there is a word in str.
Instead of allocating memory of fixed size (i.e. 200) to parsed array pointers, allocate memory of size of word only.
Few suggestions:
Always check the return value of function like malloc.
Make sure to free the dynamically allocated memory once your program done with it.
You can achieve what you want in a simpler way.
First, define a function that checks if a character (separator) is present in a list of characters (separators):
// Returns true if c is found in a list of separators, false otherwise.
bool belongs(const char c, const char *list)
{
for (const char *p = list; *p; ++p)
if (*p == c) return true;
return false;
}
Then, define a function that splits a given string into tokens, separated by one or more separators:
// Splits a string into into tokens, separated by one of the separators in sep
bool split(const char *s, const char *sep, char **tokens, size_t *ntokens, const size_t maxtokens)
{
// Start with zero tokens.
*ntokens = 0;
const char *start = s, *end = s;
for (const char *p = s; /*no condtition*/; ++p) {
// Can no longer hold more tokens? Exit.
if (*ntokens == maxtokens)
return false;
// Not a token? Continue looping.
if (*p && !belongs(*p, sep))
continue;
// Found a token: calculate its length.
size_t tlength = p - start;
// Empty token?
if (tlength == 0) {
// And reached the end of string? Break.
if (!*p) break;
// Not the end of string? Skip it.
++start;
continue;
}
// Attempt to allocate memory.
char *token = malloc(sizeof(*token) * (tlength + 1));
// Failed? Exit.
if (!token)
return false;
// Copy the token.
strncpy(token, start, tlength+1);
token[tlength] = '\0';
// Put it in tokens array.
tokens[*ntokens] = token;
// Update the number of tokens.
*ntokens += 1;
// Reached the end of string? Break.
if (!*p) break;
// There is more to parse. Set the start to the next char.
start = p + 1;
}
return true;
}
Call it like this:
int main(void)
{
char command[] = "command -par1 -par2 thing";
const size_t maxtokens = 10;
char **tokens = malloc(sizeof *tokens * maxtokens);
if (!tokens) return 1;
size_t ntokens = 0;
split(command, " ", tokens, &ntokens, maxtokens);
// Print all tokens.
printf("Number of tokens = %ld\n", ntokens);
for (size_t i = 0; i < ntokens; ++i)
printf("%s\n", tokens[i]);
// Release memory when done.
for (size_t i = 0; i < ntokens; ++i)
free(tokens[i]);
free(tokens);
}
Output:
Number of tokens = 4
command
-par1
-par2
thing
I know its a question that been asked many times before, but i'm not asking for the solution itself, but to know why my solution isn't working.
this is my solution:
void delete_blanks(char *string)
{
while (*string)
{
if (*string == ' ')
*string = '\0';
*string++;
}
puts(string);
}
The program just printing blanks (" ") for every input.
while running with the debugger, I saw that *string is pointing for '\0' at the end. Is it possible to do it "in-place"?
This is the original solution found here:
void RemoveSpaces(char* source)
{
char* i = source;
char* j = source;
while(*j != 0)
{
*i = *j++;
if(*i != ' ')
i++;
}
*i = 0;
}
Here is a good in-place implementation
int main(void) {
char inStr[] = "a cat is on the moon";
int end = 0;
for (int i = 0; i < strlen(inStr); i++) {
if (inStr[i] != ' ') {
if (i != end) {
inStr[end] = inStr[i];
}
end++;
}
}
inStr[end] = '\0';
printf("%s\n", inStr);
}
Probably because you are modifying the source, the parameter passed to that function, when it looks for spaces, shortcut the source to '\0', so you are not printing the correct result. try to use other pointers like the examples you give.
char a[]="it is a sunny morning";
int j=0;
for( int i=0;i<strlen(a);i++){
if(a[i]!=' '){
a[j]=a[i];
j++;
}
}
for(int i=j;i<strlen(a);i++){
a[i]='\0';
}
printf("%s",a);
first group the letters without space then remove the letters that exceeds the space.
output
itisasunnymorning
It's unclear what you mean by "removing the blanks". If all you want to do is print the string without the spaces, you could reduce you function to this:
void delete_blanks(char *string)
{
while (*string)
{
if (*string != ' ')
putchar(*string);
string++;
}
putchar('\n');
}
If you want to remove the spaces in the underlying string it becomes a bit more complex as you would have to move characters after a ' ' to fill in the gaps. There is no 'empty character' you can insert to fill the hole in the string, you must move the remaining characters to fill it.
Basically there a 2 major things wrong with your function. You are replacing spaces with string terminating characters, signaling that the string ends here. This is not what you want to do as there might be characters after the space. In fact, if you only want to print the string you should not be modifying it at all.
When you are done iterating over the string, string points to the end of the string. Essentially passing an empty string to puts(). You need to pass the original value, before you did a lot of ++ on it, to puts()
You are also doing *string++ when you should really be doing string++. This actually works since it is parsed as *(string++) but is terrible for readability.
If you want to remove the spaces between the words of a string,
the direct answer as follows:
// #include <ctype.h>
void RemoveSpaces(char *str) {
char *strBuff = (char*) malloc(strlen(str) + 1), *p = strBuff;
while (*str) {
if (!isspace(*str)) {
*p = *str;
p++;
}
str++;
}
*p = '\0';
printf("%s\n", strBuff);
free(strBuff);
}
int main(){
RemoveSpaces("Thank you for help");
}
The Result:
Also, there is another way and gives the same result as follows:
void RemoveSpaces(char *str) {
while (*str) {
if (!isspace(*str)) {
putchar(*str);
}
str++;
}
printf("%s\n", str);
}
I need to copy a sentence, for example "Hello world" into a string list, meaning into a char array where every 2 words are seperated by a '\0'.
note that word is defined as any amount of characters in a row without a white spaces.
So whenever my program detects any amount of white spaces in a row (including only 1 white space) it should wtire a single '\0' instead.
the problem is that after writting '\0' for the first time in my target char array, I can't write to it anymore. I guess its because '\0' means end of string but in my case I'm trying to implement a string list inside char array so I must have '\0' between every 2 words.
Basically my question is how can I countinue writing to char array after putting '\0'?
Here is my code so far (as you can see I also check for enough space in traget at every iteration but that part works fine so isn't really intersting)
int strListFromWords(const char* source, char* target, int buffSize)
{
if (buffSize < 2) return -1;
char* sCurrentPointer = source;
char* tCurrentPointer = target;
int charsInTarget = 0;
while (*sCurrentPointer != '\0') // While not end of string
{
if (charsInTarget + 2 < buffSize) // if there is enough space in target for current char
{
charsInTarget++;
if (!isspace(*sCurrentPointer)) // if current char isn't space
{
*tCurrentPointer = *sCurrentPointer;
sCurrentPointer++;
tCurrentPointer++;
}
else
{
*tCurrentPointer = '\0'; // PROBLEMATIC LINE put '\0' instead of spcace (in target)
sCurrentPointer++; // goto next char in source
tCurrentPointer++; // goto next position in target
while (isspace(*sCurrentPointer)) // while there are more spaces in a row
{
sCurrentPointer++; // just skip them without messing with target
}
}
}
else
{ // Not enough space
emptyStrList(target);
return 0;
}
}
*tCurrentPointer = '\0';
*(tCurrentPointer + 1) = '\0';
return numStrsInList(target);
}
Thank you,
There is nothing to prevent you to write past 0.
I tested your function with the following snippet, and it returns word_count correctly. The target buffer will contain the 0 terminated words, plus an extra 0 at the end. I guess, that was the intention.
#include <conio.h> // for getch()
#include <malloc.h>
#include <string.h>
int main()
{
char* source = " Hello World!\nThis is line number two.\n\n \n \n This is the last line";
size_t buflen = strlen(source);
char* target = (char*)malloc(strlen(source));
int word_count = strListFromWords(source, target, buflen);
printTarget(target);
free(target);
getch();
}
This function will show you the whole target buffer:
void printTarget(const char* target) {
char prev = ' ';
for (int i = 0;; i++) {
if (target[i])
putch(target[i]);
else {
putch('\n');
if (!prev)
break;
}
prev = target[i];
}
}
Some minor changes were necessary, to make it compile:
#include <stdio.h>
#include <ctype.h>
int strListFromWords(const char* source, char* target, int buffSize)
{
if (buffSize < 2) return -1;
char* sCurrentPointer = (char*)source;
char* tCurrentPointer = target;
int charsInTarget = 0;
int numStrsInList = 0;
while (*sCurrentPointer != '\0') // While not end of string
{
if (charsInTarget + 2 < buffSize) // if there is enough space in target for current char
{
charsInTarget++;
if (!isspace(*sCurrentPointer)) // if current char isn't space
{
*tCurrentPointer = *sCurrentPointer;
sCurrentPointer++;
tCurrentPointer++;
}
else
{
*tCurrentPointer = '\0'; // PROBLEMATIC LINE put '\0' instead of spcace (in target)
numStrsInList++;
sCurrentPointer++; // goto next char in source
tCurrentPointer++; // goto next position in target
while (isspace(*sCurrentPointer)) // while there are more spaces in a row
{
sCurrentPointer++; // just skip them without messing with target
}
}
}
else
{ // Not enough space
//emptyStrList(target);
return 0;
}
}
*tCurrentPointer = 0;
*(tCurrentPointer + 1) = 0;
return numStrsInList;
}
Pls note, I addressed only what was asked.
I suppose the main problem lies in the formulation of the requirement.
If the requirement is "split a sentence into words", then the result should be an array of "words", meaning an array of strings. If this were the requirement, then the function should have a signature like char **getWordsArrayFromSentence(const char* sentence). As you come up with a different signature, I think that your requirement is something different.
The signature of your method is int strListFromWords(const char* source, char* target, int buffSize), which indicates that it is about copying from source to target while replacing every sequence of white spaces with a single delimiter.
If you chose, for example, character ; as delimiter, then the result for sentence "Hello world" should be "Hello;world"; You can print the result, e.g. with printf("%s", target), and can check whether your algorithm works fine.
However, if you chose string termination character '\0' as delimiter, then the result looks as if it only contained the first word (although the remainder of target will contain the other words as well): target would be "Hello\0world\0" with \0 standing for string termination character. When you then print out target with printf("%s", target), then the output is Hello, i.e. the content of target until the first string termination character.
Hence, signature int strListFromWords(const char* source, char* target, int buffSize) yields a single consolidated sequence of characters but not a "list" of words; the "words" are actually contained in target, but you do not have a data structure that lets you directly access each word at its beginning.
BTW: note that the following lines are problematic,
*tCurrentPointer = "\0";
*(tCurrentPointer + 1) = "\0";
because you assign to *tCurrentPointer, which is a character within target, a pointer value, i.e. the pointer to string "\0"; Instead, you should write
*tCurrentPointer = '\0';
*(tCurrentPointer + 1) = '\0';
(Note the single quotes).
You were not very far. Ok there are still some problems to fix:
int strListFromWords(const char* source, char* target, int buffSize)
{
if (buffSize < 2) return -1;
//char* sCurrentPointer = source; lose const qualifier
const char* sCurrentPointer = source; // better!
or even better:
int strListFromWords(const char* sCurrentPointer, char* target, int buffSize)
{
if (buffSize < 2) return -1;
char* tCurrentPointer = target;
and mainly:
/* *tCurrentPointer = "\0";
*(tCurrentPointer + 1) = "\0"; NO! "\0" is a char ARRAY */
*tCurrentPointer = '\0';
*(tCurrentPointer + 1) = '\0';
But apart from that you code does what it is expected to... The terminating '\0' does not lock the array. It just mark an end of string that will be used but all string functions, but provided you are still inside the array you can write past the '\0'.
You can control it with that code:
int numStrsInList(char *target) {
int n = 0;
while (*target) {
target += strlen(target) + 1; // skip past the '\0'
n += 1;
}
return n;
}
int strListFromWords(const char* source, char* target, int buffSize)
...
int main() {
char target[32];
char src[] = "Hello to the world";
int n;
char *ix = target;
n = strListFromWords(src, target, sizeof(target));
printf("%d words:", n);
while (*ix) {
printf(" >%s<", ix);
ix += strlen(ix) + 1;
}
putchar('\n');
return 0;
}
This outputs as expected:
4 words: >Hello< >to< >the< >world<
*tCurrentPointer = "\0";
*tCurrentPointer has type char; you cannot assign an array (or a pointer after the automatic conversion) to a char.
I suggest you turn on all your compiler warnings and heed them.
I want to write a program in C that displays each word of a whole sentence (taken as input) at a seperate line. This is what I have done so far:
void manipulate(char *buffer);
int get_words(char *buffer);
int main(){
char buff[100];
printf("sizeof %d\nstrlen %d\n", sizeof(buff), strlen(buff)); // Debugging reasons
bzero(buff, sizeof(buff));
printf("Give me the text:\n");
fgets(buff, sizeof(buff), stdin);
manipulate(buff);
return 0;
}
int get_words(char *buffer){ // Function that gets the word count, by counting the spaces.
int count;
int wordcount = 0;
char ch;
for (count = 0; count < strlen(buffer); count ++){
ch = buffer[count];
if((isblank(ch)) || (buffer[count] == '\0')){ // if the character is blank, or null byte add 1 to the wordcounter
wordcount += 1;
}
}
printf("%d\n\n", wordcount);
return wordcount;
}
void manipulate(char *buffer){
int words = get_words(buffer);
char *newbuff[words];
char *ptr;
int count = 0;
int count2 = 0;
char ch = '\n';
ptr = buffer;
bzero(newbuff, sizeof(newbuff));
for (count = 0; count < 100; count ++){
ch = buffer[count];
if (isblank(ch) || buffer[count] == '\0'){
buffer[count] = '\0';
if((newbuff[count2] = (char *)malloc(strlen(buffer))) == NULL) {
printf("MALLOC ERROR!\n");
exit(-1);
}
strcpy(newbuff[count2], ptr);
printf("\n%s\n",newbuff[count2]);
ptr = &buffer[count + 1];
count2 ++;
}
}
}
Although the output is what I want, I have really many black spaces after the final word displayed, and the malloc() returns NULL so the MALLOC ERROR! is displayed in the end.
I can understand that there is a mistake at my malloc() implementation, but I do not know what it is.
Is there another more elegant or generally better way to do it?
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
Take a look at this, and use whitespace characters as the delimiter. If you need more hints let me know.
From the website:
char * strtok ( char * str, const char * delimiters );
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
Once the terminating null character of str is found in a call to strtok, all subsequent calls to this function (with a null pointer as the first argument) return a null pointer.
Parameters
str
C string to truncate.
Notice that this string is modified by being broken into smaller strings (tokens).
Alternativelly [sic], a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
delimiters
C string containing the delimiter characters.
These may vary from one call to another.
Return Value
A pointer to the last token found in string.
A null pointer is returned if there are no tokens left to retrieve.
Example
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
For the fun of it here's an implementation based on the callback approach:
const char* find(const char* s,
const char* e,
int (*pred)(char))
{
while( s != e && !pred(*s) ) ++s;
return s;
}
void split_on_ws(const char* s,
const char* e,
void (*callback)(const char*, const char*))
{
const char* p = s;
while( s != e ) {
s = find(s, e, isspace);
callback(p, s);
p = s = find(s, e, isnotspace);
}
}
void handle_word(const char* s, const char* e)
{
// handle the word that starts at s and ends at e
}
int main()
{
split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
malloc(0) may (optionally) return NULL, depending on the implementation. Do you realize why you may be calling malloc(0)? Or more precisely, do you see where you are reading and writing beyond the size of your arrays?
Consider using strtok_r, as others have suggested, or something like:
void printWords(const char *string) {
// Make a local copy of the string that we can manipulate.
char * const copy = strdup(string);
char *space = copy;
// Find the next space in the string, and replace it with a newline.
while (space = strchr(space,' ')) *space = '\n';
// There are no more spaces in the string; print out our modified copy.
printf("%s\n", copy);
// Free our local copy
free(copy);
}
Something going wrong is get_words() always returning one less than the actual word count, so eventually you attempt to:
char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */
newbuff[count2] = (char *)malloc(strlen(buffer))
count2, eventually, is always one more than the number of elements you've declared for newbuff[]. Why malloc() isn't returning a valid ptr, though, I don't know.
You should be malloc'ing strlen(ptr), not strlen(buf). Also, your count2 should be limited to the number of words. When you get to the end of your string, you continue going over the zeros in your buffer and adding zero size strings to your array.
Just as an idea of a different style of string manipulation in C, here's an example which does not modify the source string, and does not use malloc. To find spaces I use the libc function strpbrk.
int print_words(const char *string, FILE *f)
{
static const char space_characters[] = " \t";
const char *next_space;
// Find the next space in the string
//
while ((next_space = strpbrk(string, space_characters)))
{
const char *p;
// If there are non-space characters between what we found
// and what we started from, print them.
//
if (next_space != string)
{
for (p=string; p<next_space; p++)
{
if(fputc(*p, f) == EOF)
{
return -1;
}
}
// Print a newline
//
if (fputc('\n', f) == EOF)
{
return -1;
}
}
// Advance next_space until we hit a non-space character
//
while (*next_space && strchr(space_characters, *next_space))
{
next_space++;
}
// Advance the string
//
string = next_space;
}
// Handle the case where there are no spaces left in the string
//
if (*string)
{
if (fprintf(f, "%s\n", string) < 0)
{
return -1;
}
}
return 0;
}
you can scan the char array looking for the token if you found it just print new line else print the char.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
int len = strlen(s);
char delim =' ';
for(int i = 0; i < len; i++) {
if(s[i] == delim) {
printf("\n");
}
else {
printf("%c", s[i]);
}
}
free(s);
return 0;
}
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);
for(i=0;i<l;i++){
if(arr[i]==32){
printf("\n");
}
else
printf("%c",arr[i]);
}
This question already has answers here:
How do I trim leading/trailing whitespace in a standard way?
(40 answers)
Closed 5 years ago.
Briefly:
I'm after the equivalent of .NET's String.Trim in C using the win32 and standard C api (compiling with MSVC2008 so I have access to all the C++ stuff if needed, but I am just trying to trim a char*).
Given that there is strchr, strtok, and all manner of other string functions, surely there should be a trim function, or one that can be repurposed...
Thanks
There is no standard library function to do this, but it's not too hard to roll your own. There is an existing question on SO about doing this that was answered with source code.
This made me want to write my own - I didn't like the ones that had been provided. Seems to me there should be 3 functions.
char *ltrim(char *s)
{
while(isspace(*s)) s++;
return s;
}
char *rtrim(char *s)
{
char* back = s + strlen(s);
while(isspace(*--back));
*(back+1) = '\0';
return s;
}
char *trim(char *s)
{
return rtrim(ltrim(s));
}
You can use the standard isspace() function in ctype.h to achieve this. Simply compare the beginning and end characters of your character array until both ends no longer have spaces.
"spaces" include:
' ' (0x20) space (SPC)
'\t' (0x09) horizontal tab (TAB)
'\n' (0x0a) newline (LF)
'\v' (0x0b) vertical tab (VT)
'\f' (0x0c) feed (FF)
'\r' (0x0d) carriage return (CR)
although there is no function which will do all of the work for you, you will have to roll your own solution to compare each side of the given character array repeatedly until no spaces remain.
Edit:
Since you have access to C++, Boost has a trim implementation waiting for you to make your life a lot easier.
Surprised to see such implementations. I usually do trim like this:
char *trim(char *s) {
char *ptr;
if (!s)
return NULL; // handle NULL string
if (!*s)
return s; // handle empty string
for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr);
ptr[1] = '\0';
return s;
}
It is fast and reliable - serves me many years.
/* Function to remove white spaces on both sides of a string i.e trim */
void trim (char *s)
{
int i;
while (isspace (*s)) s++; // skip left side white spaces
for (i = strlen (s) - 1; (isspace (s[i])); i--) ; // skip right side white spaces
s[i + 1] = '\0';
printf ("%s\n", s);
}
#include "stdafx.h"
#include <string.h>
#include <ctype.h>
char* trim(char* input);
int _tmain(int argc, _TCHAR* argv[])
{
char sz1[]=" MQRFH ";
char sz2[]=" MQRFH";
char sz3[]=" MQR FH";
char sz4[]="MQRFH ";
char sz5[]="MQRFH";
char sz6[]="M";
char sz7[]="M ";
char sz8[]=" M";
char sz9[]="";
char sz10[]=" ";
printf("sz1:[%s] %d\n",trim(sz1), strlen(sz1));
printf("sz2:[%s] %d\n",trim(sz2), strlen(sz2));
printf("sz3:[%s] %d\n",trim(sz3), strlen(sz3));
printf("sz4:[%s] %d\n",trim(sz4), strlen(sz4));
printf("sz5:[%s] %d\n",trim(sz5), strlen(sz5));
printf("sz6:[%s] %d\n",trim(sz6), strlen(sz6));
printf("sz7:[%s] %d\n",trim(sz7), strlen(sz7));
printf("sz8:[%s] %d\n",trim(sz8), strlen(sz8));
printf("sz9:[%s] %d\n",trim(sz9), strlen(sz9));
printf("sz10:[%s] %d\n",trim(sz10), strlen(sz10));
return 0;
}
char *ltrim(char *s)
{
while(isspace(*s)) s++;
return s;
}
char *rtrim(char *s)
{
char* back;
int len = strlen(s);
if(len == 0)
return(s);
back = s + len;
while(isspace(*--back));
*(back+1) = '\0';
return s;
}
char *trim(char *s)
{
return rtrim(ltrim(s));
}
Output:
sz1:[MQRFH] 9
sz2:[MQRFH] 6
sz3:[MQR FH] 8
sz4:[MQRFH] 7
sz5:[MQRFH] 5
sz6:[M] 1
sz7:[M] 2
sz8:[M] 2
sz9:[] 0
sz10:[] 8
I like it when the return value always equals the argument. This way, if the string array has been allocated with malloc(), it can safely be free() again.
/* Remove leading whitespaces */
char *ltrim(char *const s)
{
size_t len;
char *cur;
if(s && *s) {
len = strlen(s);
cur = s;
while(*cur && isspace(*cur))
++cur, --len;
if(s != cur)
memmove(s, cur, len + 1);
}
return s;
}
/* Remove trailing whitespaces */
char *rtrim(char *const s)
{
size_t len;
char *cur;
if(s && *s) {
len = strlen(s);
cur = s + len - 1;
while(cur != s && isspace(*cur))
--cur, --len;
cur[isspace(*cur) ? 0 : 1] = '\0';
}
return s;
}
/* Remove leading and trailing whitespaces */
char *trim(char *const s)
{
rtrim(s); // order matters
ltrim(s);
return s;
}
void ltrim(char str[PATH_MAX])
{
int i = 0, j = 0;
char buf[PATH_MAX];
strcpy(buf, str);
for(;str[i] == ' ';i++);
for(;str[i] != '\0';i++,j++)
buf[j] = str[i];
buf[j] = '\0';
strcpy(str, buf);
}
static inline void ut_trim(char * str) {
char * start = str;
char * end = start + strlen(str);
while (--end >= start) { /* trim right */
if (!isspace(*end))
break;
}
*(++end) = '\0';
while (isspace(*start)) /* trim left */
start++;
if (start != str) /* there is a string */
memmove(str, start, end - start + 1);
}
How about this... It only requires one iteration over the string (doesn't use strlen, which iterates over the string). When the function returns you get a pointer to the start of the trimmed string which is null terminated. The string is trimmed of spaces from the left (until the first character is found). The string is also trimmed of all trailing spaces after the last nonspace character.
char* trim(char* input) {
char* start = input;
while (isSpace(*start)) { //trim left
start++;
}
char* ptr = start;
char* end = start;
while (*ptr++ != '\0') { //trim right
if (!isSpace(*ptr)) { //only move end pointer if char isn't a space
end = ptr;
}
}
*end = '\0'; //terminate the trimmed string with a null
return start;
}
bool isSpace(char c) {
switch (c) {
case ' ':
case '\n':
case '\t':
case '\f':
case '\r':
return true;
break;
default:
return false;
break;
}
}
/* iMode 0:ALL, 1:Left, 2:Right*/
char* Trim(char* szStr,const char ch, int iMode)
{
if (szStr == NULL)
return NULL;
char szTmp[1024*10] = { 0x00 };
strcpy(szTmp, szStr);
int iLen = strlen(szTmp);
char* pStart = szTmp;
char* pEnd = szTmp+iLen;
int i;
for(i = 0;i < iLen;i++){
if (szTmp[i] == ch && pStart == szTmp+i && iMode != 2)
++pStart;
if (szTmp[iLen-i-1] == ch && pEnd == szTmp+iLen-i && iMode != 1)
*(--pEnd) = '\0';
}
strcpy(szStr, pStart);
return szStr;
}
Here's my implementation, behaving like the built-in string functions in libc (that is, it expects a c-string, it modifies it and returns it to the caller).
It trims leading spaces & shifts the remaining chars to the left, as it parses the string from left to right. It then marks a new end of string and starts parsing it backwards, replacing trailing spaces with '\0's until it finds either a non-space char or the start of the string. I believe those are the minimum possible iterations for this particular task.
// ----------------------------------------------------------------------------
// trim leading & trailing spaces from string s (return modified string s)
// alg:
// - skip leading spaces, via cp1
// - shift remaining *cp1's to the left, via cp2
// - mark a new end of string
// - replace trailing spaces with '\0', via cp2
// - return the trimmed s
//
char *s_trim(char *s)
{
char *cp1; // for parsing the whole s
char *cp2; // for shifting & padding
// skip leading spaces, shift remaining chars
for (cp1=s; isspace(*cp1); cp1++ ) // skip leading spaces, via cp1
;
for (cp2=s; *cp1; cp1++, cp2++) // shift left remaining chars, via cp2
*cp2 = *cp1;
*cp2-- = 0; // mark new end of string for s
// replace trailing spaces with '\0'
while ( cp2 > s && isspace(*cp2) )
*cp2-- = 0; // pad with '\0's
return s;
}
Not the best way but it works
char* Trim(char* str)
{
int len = strlen(str);
char* buff = new char[len];
int i = 0;
memset(buff,0,len*sizeof(char));
do{
if(isspace(*str)) continue;
buff[i] = *str; ++i;
} while(*(++str) != '\0');
return buff;
}
void inPlaceStrTrim(char* str) {
int k = 0;
int i = 0;
for (i=0; str[i] != '\0';) {
if (isspace(str[i])) {
// we have got a space...
k = i;
for (int j=i; j<strlen(str)-1; j++) {
str[j] = str[j+1];
}
str[strlen(str)-1] = '\0';
i = k; // start the loop again where we ended..
} else {
i++;
}
}
}
Easiest thing to do is a simple loop. I'm going to assume that you want the trimmed string returned in place.
char *
strTrim(char * s){
int ix, jx;
int len ;
char * buf
len = strlen(s); /* possibly should use strnlen */
buf = (char *) malloc(strlen(s)+1);
for(ix=0, jx=0; ix < len; ix++){
if(!isspace(s[ix]))
buf[jx++] = s[ix];
buf[jx] = '\0';
strncpy(s, buf, jx); /* always looks as far as the null, but who cares? */
free(buf); /* no good leak goes unpunished */
return s; /* modifies s in place *and* returns it for swank */
}
This gets rid of embedded blanks too, if String.Trim doesn't then it needs a bit more logic.