¿Cómo recorto el espacio en blanco inicial / final de una manera estándar?

¿Existe un método limpio, preferiblemente estándar, para recortar los espacios en blanco iniciales y finales de una cuerda en C? Me gustaría ganar, pero creo que este es un problema común con una solución igualmente común.

Si puedes modificar la cadena:

// Note: This function returns a pointer to a substring of the original string. // If the given string was allocated dynamically, the caller must not overwrite // that pointer with the returned value, since the original pointer must be // deallocated using the same allocator with which it was allocated. The return // value must NOT be deallocated using free() etc. char *trimwhitespace(char *str) { char *end; // Trim leading space while(isspace((unsigned char)*str)) str++; if(*str == 0) // All spaces? return str; // Trim trailing space end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; // Write new null terminator character end[1] = '\0'; return str; } 

Si no puede modificar la cadena, puede usar básicamente el mismo método:

 // Stores the trimmed input string into the given output buffer, which must be // large enough to store the result. If it is too small, the output is // truncated. size_t trimwhitespace(char *out, size_t len, const char *str) { if(len == 0) return 0; const char *end; size_t out_size; // Trim leading space while(isspace((unsigned char)*str)) str++; if(*str == 0) // All spaces? { *out = 0; return 1; } // Trim trailing space end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; end++; // Set output size to minimum of trimmed string length and buffer size minus 1 out_size = (end - str) < len-1 ? (end - str) : len-1; // Copy trimmed string and add null terminator memcpy(out, str, out_size); out[out_size] = 0; return out_size; } 

Aquí hay uno que cambia la cuerda a la primera posición de tu buffer. Es posible que desee este comportamiento para que, si asignó dinámicamente la cadena, aún pueda liberarlo en el mismo puntero que devuelve trim ():

 char *trim(char *str) { size_t len = 0; char *frontp = str; char *endp = NULL; if( str == NULL ) { return NULL; } if( str[0] == '\0' ) { return str; } len = strlen(str); endp = str + len; /* Move the front and back pointers to address the first non-whitespace * characters from each end. */ while( isspace((unsigned char) *frontp) ) { ++frontp; } if( endp != frontp ) { while( isspace((unsigned char) *(--endp)) && endp != frontp ) {} } if( str + len - 1 != endp ) *(endp + 1) = '\0'; else if( frontp != str && endp == frontp ) *str = '\0'; /* Shift the string so that it starts at str so that if it's dynamically * allocated, we can still free it on the returned pointer. Note the reuse * of endp to mean the front of the string buffer now. */ endp = str; if( frontp != str ) { while( *frontp ) { *endp++ = *frontp++; } *endp = '\0'; } return str; } 

Prueba de corrección:

 int main(int argc, char *argv[]) { char *sample_strings[] = { "nothing to trim", " trim the front", "trim the back ", " trim one char front and back ", " trim one char front", "trim one char back ", " ", " ", "a", "", NULL }; char test_buffer[64]; int index; for( index = 0; sample_strings[index] != NULL; ++index ) { strcpy( test_buffer, sample_strings[index] ); printf("[%s] -> [%s]\n", sample_strings[index], trim(test_buffer)); } /* The test prints the following: [nothing to trim] -> [nothing to trim] [ trim the front] -> [trim the front] [trim the back ] -> [trim the back] [ trim one char front and back ] -> [trim one char front and back] [ trim one char front] -> [trim one char front] [trim one char back ] -> [trim one char back] [ ] -> [] [ ] -> [] [a] -> [a] [] -> [] */ return 0; } 

El archivo fuente fue trim.c. Comstackdo con ‘cc trim.c -o trim’.

Mi solución. La cadena debe ser cambiable. La ventaja sobre algunas de las otras soluciones es que mueve la parte no espacial al principio para que pueda seguir usando el puntero anterior, en caso de que tenga que liberarlo () más tarde.

 void trim(char * s) { char * p = s; int l = strlen(p); while(isspace(p[l - 1])) p[--l] = 0; while(* p && isspace(* p)) ++p, --l; memmove(s, p, l + 1); } 

Esta versión crea una copia de la cadena con strndup () en lugar de editarla en su lugar. strndup () requiere _GNU_SOURCE, por lo que tal vez necesites crear tu propio strndup () con malloc () y strncpy ().

 char * trim(char * s) { int l = strlen(s); while(isspace(s[l - 1])) --l; while(* s && isspace(* s)) ++s, --l; return strndup(s, l); } 

Aquí está mi bash de una función de recorte en el lugar simple pero correcta.

 void trim(char *str) { int i; int begin = 0; int end = strlen(str) - 1; while (isspace((unsigned char) str[begin])) begin++; while ((end >= begin) && isspace((unsigned char) str[end])) end--; // Shift all characters back to the start of the string array. for (i = begin; i <= end; i++) str[i - begin] = str[i]; str[i - begin] = '\0'; // Null terminate string. } 

Aquí está mi mini biblioteca C para recortar a la izquierda, a la derecha, a ambas, todas, en su lugar y separadas, y recortar un conjunto de caracteres especificados (o espacio en blanco de forma predeterminada).

contenido de strlib.h:

 #ifndef STRLIB_H_ #define STRLIB_H_ 1 enum strtrim_mode_t { STRLIB_MODE_ALL = 0, STRLIB_MODE_RIGHT = 0x01, STRLIB_MODE_LEFT = 0x02, STRLIB_MODE_BOTH = 0x03 }; char *strcpytrim(char *d, // destination char *s, // source int mode, char *delim ); char *strtriml(char *d, char *s); char *strtrimr(char *d, char *s); char *strtrim(char *d, char *s); char *strkill(char *d, char *s); char *triml(char *s); char *trimr(char *s); char *trim(char *s); char *kill(char *s); #endif 

contenidos de strlib.c:

 #include  char *strcpytrim(char *d, // destination char *s, // source int mode, char *delim ) { char *o = d; // save orig char *e = 0; // end space ptr. char dtab[256] = {0}; if (!s || !d) return 0; if (!delim) delim = " \t\n\f"; while (*delim) dtab[*delim++] = 1; while ( (*d = *s++) != 0 ) { if (!dtab[0xFF & (unsigned int)*d]) { // Not a match char e = 0; // Reset end pointer } else { if (!e) e = d; // Found first match. if ( mode == STRLIB_MODE_ALL || ((mode != STRLIB_MODE_RIGHT) && (d == o)) ) continue; } d++; } if (mode != STRLIB_MODE_LEFT && e) { // for everything but trim_left, delete trailing matches. *e = 0; } return o; } // perhaps these could be inlined in strlib.h char *strtriml(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_LEFT, 0); } char *strtrimr(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_RIGHT, 0); } char *strtrim(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_BOTH, 0); } char *strkill(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_ALL, 0); } char *triml(char *s) { return strcpytrim(s, s, STRLIB_MODE_LEFT, 0); } char *trimr(char *s) { return strcpytrim(s, s, STRLIB_MODE_RIGHT, 0); } char *trim(char *s) { return strcpytrim(s, s, STRLIB_MODE_BOTH, 0); } char *kill(char *s) { return strcpytrim(s, s, STRLIB_MODE_ALL, 0); } 

La rutina principal lo hace todo. Ajusta en su lugar si src == dst , de lo contrario, funciona como las rutinas strcpy . Recorta un conjunto de caracteres especificados en el delimitador de cadena, o espacio en blanco si es nulo. Ajusta a la izquierda, a la derecha, a ambos y a todos (como tr). No hay mucho para eso, e itera sobre la cadena solo una vez. Algunas personas pueden quejarse de que el ajuste derecho comienza a la izquierda, sin embargo, no se necesita ningún ajuste que comience a la izquierda de todos modos. (De una manera u otra, tiene que llegar al final de la cadena para los ajustes correctos, por lo que también puede hacer el trabajo sobre la marcha). Puede haber argumentos que se deben hacer sobre la canalización y los tamaños de la memoria caché, y quién sabe. . Dado que la solución funciona de izquierda a derecha y se repite solo una vez, también se puede expandir para trabajar en las transmisiones. Limitaciones: no funciona en cadenas Unicode .

Aquí hay una solución similar a la rutina de modificación in situ de @ adam-rosenfields, pero sin recurrir innecesariamente a strlen (). Al igual que @jkramer, la cadena se ajusta a la izquierda dentro del buffer para que pueda liberar el mismo puntero. No es óptimo para cadenas grandes ya que no usa memmove. Incluye los operadores ++ / – que menciona @ jfm3. Pruebas unitarias basadas en FCTX incluidas.

 #include  void trim(char * const a) { char *p = a, *q = a; while (isspace(*q)) ++q; while (*q) *p++ = *q++; *p = '\0'; while (p > a && isspace(*--p)) *p = '\0'; } /* See http://fctx.wildbearsoftware.com/ */ #include "fct.h" FCT_BGN() { FCT_QTEST_BGN(trim) { { char s[] = ""; trim(s); fct_chk_eq_str("", s); } // Trivial { char s[] = " "; trim(s); fct_chk_eq_str("", s); } // Trivial { char s[] = "\t"; trim(s); fct_chk_eq_str("", s); } // Trivial { char s[] = "a"; trim(s); fct_chk_eq_str("a", s); } // NOP { char s[] = "abc"; trim(s); fct_chk_eq_str("abc", s); } // NOP { char s[] = " a"; trim(s); fct_chk_eq_str("a", s); } // Leading { char s[] = " ac"; trim(s); fct_chk_eq_str("ac", s); } // Leading { char s[] = "a "; trim(s); fct_chk_eq_str("a", s); } // Trailing { char s[] = "ac "; trim(s); fct_chk_eq_str("ac", s); } // Trailing { char s[] = " a "; trim(s); fct_chk_eq_str("a", s); } // Both { char s[] = " ac "; trim(s); fct_chk_eq_str("ac", s); } // Both // Villemoes pointed out an edge case that corrupted memory. Thank you. // http://stackoverflow.com/questions/122616/#comment23332594_4505533 { char s[] = "a "; // Buffer with whitespace before s + 2 trim(s + 2); // Trim " " containing only whitespace fct_chk_eq_str("", s + 2); // Ensure correct result from the trim fct_chk_eq_str("a ", s); // Ensure preceding buffer not mutated } // doukremt suggested I investigate this test case but // did not indicate the specific behavior that was objectionable. // http://stackoverflow.com/posts/comments/33571430 { char s[] = " foobar"; // Shifted across whitespace trim(s); // Trim fct_chk_eq_str("foobar", s); // Leading string is correct // Here is what the algorithm produces: char r[16] = { 'f', 'o', 'o', 'b', 'a', 'r', '\0', ' ', ' ', 'f', 'o', 'o', 'b', 'a', 'r', '\0'}; fct_chk_eq_int(0, memcmp(s, r, sizeof(s))); } } FCT_QTEST_END(); } FCT_END(); 

Otro, con una línea haciendo el trabajo real:

 #include  int main() { const char *target = " haha "; char buf[256]; sscanf(target, "%s", buf); // Trimming on both sides occurs here printf("<%s>\n", buf); } 

Tarde a la fiesta de ajuste

caracteristicas:
1. Recorte el comienzo rápidamente, como en varias otras respuestas.
2. Después de ir al final, recorte el derecho con solo 1 prueba por ciclo. Like @ jfm3, pero funciona para una cadena de espacio en blanco)
3. Para evitar el comportamiento indefinido cuando char es un char firmado, use *s para unsigned char .

Manejo de caracteres “En todos los casos, el argumento es un int , cuyo valor debe ser representable como un unsigned char o debe ser igual al valor del macro EOF . Si el argumento tiene algún otro valor, el comportamiento no está definido”. C11 §7.4 1

 #include  // Return a pointer to the trimmed string char *string_trim_inplace(char *s) { while (isspace((unsigned char) *s)) s++; if (*s) { char *p = s; while (*p) p++; while (isspace((unsigned char) *(--p))); p[1] = '\0'; } return s; } 

No me gustó la mayoría de estas respuestas porque hicieron una o más de las siguientes …

  1. Devolvió un puntero diferente dentro de la cadena del puntero original (una especie de dolor para hacer malabarismos con dos punteros diferentes a la misma cosa).
  2. Hizo uso gratuito de cosas como strlen () que pre-iteran toda la cadena.
  3. Usó funciones de lib específicas del sistema operativo no portátiles.
  4. Backscanned.
  5. Se usa la comparación con ” en lugar de isspace () para que TAB / CR / LF se conserven.
  6. Memoria desperdiciada con grandes búfers estáticos.
  7. Ciclos perdidos con funciones de alto costo como sscanf / sprintf .

Aquí está mi versión:

 void fnStrTrimInPlace(char *szWrite) { const char *szWriteOrig = szWrite; char *szLastSpace = szWrite, *szRead = szWrite; int bNotSpace; // SHIFT STRING, STARTING AT FIRST NON-SPACE CHAR, LEFTMOST while( *szRead != '\0' ) { bNotSpace = !isspace((unsigned char)(*szRead)); if( (szWrite != szWriteOrig) || bNotSpace ) { *szWrite = *szRead; szWrite++; // TRACK POINTER TO LAST NON-SPACE if( bNotSpace ) szLastSpace = szWrite; } szRead++; } // TERMINATE AFTER LAST NON-SPACE (OR BEGINNING IF THERE WAS NO NON-SPACE) *szLastSpace = '\0'; } 

La forma más fácil de omitir espacios principales en una cadena es, imho,

 #include  int main() { char *foo=" teststring "; char *bar; sscanf(foo,"%s",bar); printf("String is >%s<\n",bar); return 0; } 

Muy tarde a la fiesta …

Solución de escaneo directo de un solo paso sin retroceso. Cada personaje en la cadena fuente se prueba exactamente una vez. (Así que debería ser más rápido que la mayoría de las otras soluciones aquí, especialmente si la cadena fuente tiene muchos espacios finales).

Esto incluye dos soluciones, una para copiar y recortar una cadena fuente en otra cadena de destino, y la otra para recortar la cadena fuente en su lugar. Ambas funciones usan el mismo código.

La cadena (modificable) se mueve en el lugar, por lo que el puntero original permanece inalterado.

 #include  #include  char * trim2(char *d, const char *s) { // Sanity checks if (s == NULL || d == NULL) return NULL; // Skip leading spaces unsigned const char * p = (unsigned const char *)s; while (isspace(*p)) p++; // Copy the string unsigned char * dst = (unsigned char *)d; // d and s can be the same unsigned char * end = dst; while (*p != '\0') { if (!isspace(*dst++ = *p++)) end = dst; } // Truncate trailing spaces *end = '\0'; return d; } char * trim(char *s) { return trim2(s, s); } 

Use una biblioteca de cadenas , por ejemplo:

 Ustr *s1 = USTR1(\7, " 12345 "); ustr_sc_trim_cstr(&s1, " "); assert(ustr_cmp_cstr_eq(s1, "12345")); 

… como dices, este es un problema “común”, sí, necesitas incluir un #include más o menos y no está incluido en libc pero no vas a inventar tu propio trabajo de hackeo almacenando punteros aleatorios y size_t’s de esa manera solo te lleva a desbordamientos de búfer.

 #include "stdafx.h" #include "malloc.h" #include "string.h" int main(int argc, char* argv[]) { char *ptr = (char*)malloc(sizeof(char)*30); strcpy(ptr," Hel lo wo rl d G eo rocks!!! by shahil sucks big tim e"); int i = 0, j = 0; while(ptr[j]!='\0') { if(ptr[j] == ' ' ) { j++; ptr[i] = ptr[j]; } else { i++; j++; ptr[i] = ptr[j]; } } printf("\noutput-%s\n",ptr); return 0; } 

s fue extremadamente útil, quería decir que estaba contento de que esta publicación estuviera disponible y de mostrar lo que pude hacer con los ejemplos. Necesitaba tokenizar una cadena más grande, y luego tomar la (s) subcadenas (s) y encontrar la última – para poder eliminar una nueva línea de la llamada de fgets (), y también eliminar el espacio en blanco del frente de esa ficha – para poder compararlo fácilmente con una cuerda estática. El primer ejemplo en la publicación anterior me llevó allí, así que gracias. Aquí es cómo utilicé las muestras de código y la salida que obtuve.

 int _tmain(int argc, _TCHAR* argv[]) { FILE * fp; // test file char currDBSStatstr[100] = {"/0"}; char *beg; char *end; char *str1; char str[] = "Initializing DBS Configuration"; fp = fopen("file2-1.txt","r"); if (fp != NULL) { printf("File exists.\n"); fgets(currDBSStatstr, sizeof(currDBSStatstr), fp); } else { printf("Error.\n"); exit(2); } //print string printf("String: %s\n", currDBSStatstr); //extract first string str1 = strtok(currDBSStatstr, ":-"); //print first token printf("%s\n", str1); //get more tokens in sequence while(1) { //extract more tokens in sequence str1 = strtok(NULL, ":-"); //check to see if done if (str1 == NULL) { printf("Tokenizing Done.\n"); exit(0); } //print string after tokenizing Done printf("%s\n", str1); end = str1 + strlen(str1) - 1; while((end > str1) && (*end == '\n')) { end--; *(end+1) = 0; beg = str1; while(isspace(*str1)) str1++; } printf("%s\n", str1); if (strcmp(str, str1) == 0) printf("Strings are equal.\n"); } return 0; 

}

Salida

El archivo existe.

Cadena: Estado de DBS: Inicio de DBS – Inicialización de la configuración de DBS

Estado de DBS

Inicio de DBS

Inicio de DBS

Inicializando la configuración de DBS

Inicializando la configuración de DBS

Las cadenas son iguales.

Tokenizing Hecho.

Si usa glib , puede usar g_strstrip

Solo para mantener esto creciendo, una opción más con una cadena modificable:

 void trimString(char *string) { size_t i = 0, j = strlen(string); while (j > 0 && isspace((unsigned char)string[j - 1])) string[--j] = '\0'; while (isspace((unsigned char)string[i])) i++; if (i > 0) memmove(string, string + i, j - i + 1); } 

Sé que hay muchas respuestas, pero publico mi respuesta aquí para ver si mi solución es lo suficientemente buena.

 // Trims leading whitespace chars in left `str`, then copy at almost `n - 1` chars // into the `out` buffer in which copying might stop when the first '\0' occurs, // and finally append '\0' to the position of the last non-trailing whitespace char. // Reture the length the trimed string which '\0' is not count in like strlen(). size_t trim(char *out, size_t n, const char *str) { // do nothing if(n == 0) return 0; // ptr stop at the first non-leading space char while(isspace(*str)) str++; if(*str == '\0') { out[0] = '\0'; return 0; } size_t i = 0; // copy char to out until '\0' or i == n - 1 for(i = 0; i < n - 1 && *str != '\0'; i++){ out[i] = *str++; } // deal with the trailing space while(isspace(out[--i])); out[++i] = '\0'; return i; } 

Personalmente, yo haría mi propio. Puede usar strtok, pero debe tener cuidado al hacerlo (especialmente si está eliminando caracteres principales) para saber qué memoria es qué.

Deshacerse de los espacios finales es fácil y bastante seguro, ya que puede poner un 0 en la parte superior del último espacio, contando desde el final. Deshacerse de los espacios principales significa mover las cosas. Si quieres hacerlo en su lugar (probablemente sensato), puedes seguir cambiando todo un personaje hasta que no haya espacio principal. O bien, para ser más eficiente, podría encontrar el índice del primer carácter que no sea espacio, y cambiarlo todo por ese número. O bien, podría usar un puntero al primer carácter que no sea espacio (pero debe tener cuidado de la misma manera que lo hace con strtok).

No estoy seguro de lo que consideras “sin dolor”.

C cadenas son bastante dolorosas. Podemos encontrar la primera posición de personaje no blanco de forma trivial:

 mientras que (isspace (* p)) p ++;

Podemos encontrar la última posición del personaje que no sea de espacio en blanco con dos movimientos triviales similares:

 while (* q) q ++;
 do {q--;  } while (isspace (* q));

(Te evité el dolor de usar los operadores * y ++ al mismo tiempo).

La pregunta ahora es ¿qué haces con esto? El tipo de datos a la mano no es realmente una String abstracta grande y robusta en String que sea fácil pensar, sino que en realidad apenas es más que una matriz de bytes de almacenamiento. Al carecer de un tipo de datos robusto, es imposible escribir una función que haga lo mismo que la función chomp de PHperytonby. ¿Qué devolvería tal función en C?

Un poco tarde para el juego, pero lanzaré mis rutinas al combate. Probablemente no sean los más eficientes, pero creo que son correctos y son simples (con rtrim() empujando la envolvente de la complejidad):

 #include  #include  /* Public domain implementations of in-place string trim functions Michael Burr michael.burr@nth-element.com 2010 */ char* ltrim(char* s) { char* newstart = s; while (isspace( *newstart)) { ++newstart; } // newstart points to first non-whitespace char (which might be '\0') memmove( s, newstart, strlen( newstart) + 1); // don't forget to move the '\0' terminator return s; } char* rtrim( char* s) { char* end = s + strlen( s); // find the last non-whitespace character while ((end != s) && isspace( *(end-1))) { --end; } // at this point either (end == s) and s is either empty or all whitespace // so it needs to be made empty, or // end points just past the last non-whitespace character (it might point // at the '\0' terminator, in which case there's no problem writing // another there). *end = '\0'; return s; } char* trim( char* s) { return rtrim( ltrim( s)); } 

La mayoría de las respuestas hasta ahora hacen una de las siguientes:

  1. Retroceda al final de la cadena (es decir, busque el final de la cadena y luego busque hacia atrás hasta encontrar un carácter que no sea de espacio) o
  2. Llame a strlen() primero, haciendo un segundo pase a través de la cadena completa.

Esta versión solo hace una pasada y no retrocede. Por lo tanto, puede funcionar mejor que los demás, aunque solo si es común tener cientos de espacios finales (lo cual no es inusual cuando se trata del resultado de una consulta SQL).

 static char const WHITESPACE[] = " \t\n\r"; static void get_trim_bounds(char const *s, char const **firstWord, char const **trailingSpace) { char const *lastWord; *firstWord = lastWord = s + strspn(s, WHITESPACE); do { *trailingSpace = lastWord + strcspn(lastWord, WHITESPACE); lastWord = *trailingSpace + strspn(*trailingSpace, WHITESPACE); } while (*lastWord != '\0'); } char *copy_trim(char const *s) { char const *firstWord, *trailingSpace; char *result; size_t newLength; get_trim_bounds(s, &firstWord, &trailingSpace); newLength = trailingSpace - firstWord; result = malloc(newLength + 1); memcpy(result, firstWord, newLength); result[newLength] = '\0'; return result; } void inplace_trim(char *s) { char const *firstWord, *trailingSpace; size_t newLength; get_trim_bounds(s, &firstWord, &trailingSpace); newLength = trailingSpace - firstWord; memmove(s, firstWord, newLength); s[newLength] = '\0'; } 

Esta es la implementación más corta posible que puedo pensar:

 static const char *WhiteSpace=" \n\r\t"; char* trim(char *t) { char *e=t+(t!=NULL?strlen(t):0); // *e initially points to end of string if (t==NULL) return; do --e; while (strchr(WhiteSpace, *e) && e>=t); // Find last char that is not \r\n\t *(++e)=0; // Null-terminate e=t+strspn (t,WhiteSpace); // Find first char that is not \t return e>t?memmove(t,e,strlen(e)+1):t; // memmove string contents and terminator } 

These functions will modify the original buffer, so if dynamically allocated, the original pointer can be freed.

 #include  void rstrip(char *string) { int l; if (!string) return; l = strlen(string) - 1; while (isspace(string[l]) && l >= 0) string[l--] = 0; } void lstrip(char *string) { int i, l; if (!string) return; l = strlen(string); while (isspace(string[(i = 0)])) while(i++ < l) string[i-1] = string[i]; } void strip(char *string) { lstrip(string); rstrip(string); } 

What do you think about using StrTrim function defined in header Shlwapi.h.? It is straight forward rather defining on your own.
Details can be found on:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773454(v=vs.85).aspx

Si usted tiene
char ausCaptain[]="GeorgeBailey ";
StrTrim(ausCaptain," ");
This will give ausCaptain as "GeorgeBailey" not "GeorgeBailey " .

To trim my strings from the both sides I use the oldie but the gooody 😉 It can trim anything with ascii less than a space, meaning that the control chars will be trimmed also !

 char *trimAll(char *strData) { unsigned int L = strlen(strData); if(L > 0){ L--; }else{ return strData; } size_t S = 0, E = L; while((!(strData[S] > ' ') || !(strData[E] > ' ')) && (S >= 0) && (S <= L) && (E >= 0) && (E <= L)) { if(strData[S] <= ' '){ S++; } if(strData[E] <= ' '){ E--; } } if(S == 0 && E == L){ return strData; } // Nothing to be done if((S >= 0) && (S <= L) && (E >= 0) && (E <= L)){ L = E - S + 1; memmove(strData,&strData[S],L); strData[L] = '\0'; }else{ strData[0] = '\0'; } return strData; } 

I’m only including code because the code posted so far seems suboptimal (and I don’t have the rep to comment yet.)

 void inplace_trim(char* s) { int start, end = strlen(s); for (start = 0; isspace(s[start]); ++start) {} if (s[start]) { while (end > 0 && isspace(s[end-1])) --end; memmove(s, &s[start], end - start); } s[end - start] = '\0'; } char* copy_trim(const char* s) { int start, end; for (start = 0; isspace(s[start]); ++start) {} for (end = strlen(s); end > 0 && isspace(s[end-1]); --end) {} return strndup(s + start, end - start); } 

strndup() is a GNU extension. If you don’t have it or something equivalent, roll your own. Por ejemplo:

 r = strdup(s + start); r[end-start] = '\0'; 

Here i use the dynamic memory allocation to trim the input string to the function trimStr. First, we find how many non-empty characters exist in the input string. Then, we allocate a character array with that size and taking care of the null terminated character. When we use this function, we need to free the memory inside of main function.

 #include #include char *trimStr(char *str){ char *tmp = str; printf("input string %s\n",str); int nc = 0; while(*tmp!='\0'){ if (*tmp != ' '){ nc++; } tmp++; } printf("total nonempty characters are %d\n",nc); char *trim = NULL; trim = malloc(sizeof(char)*(nc+1)); if (trim == NULL) return NULL; tmp = str; int ne = 0; while(*tmp!='\0'){ if (*tmp != ' '){ trim[ne] = *tmp; ne++; } tmp++; } trim[nc] = '\0'; printf("trimmed string is %s\n",trim); return trim; } int main(void){ char str[] = " s ta ck ove r fl ow "; char *trim = trimStr(str); if (trim != NULL )free(trim); return 0; } 

Here is how I do it. It trims the string in place, so no worry about deallocating a returned string or losing the pointer to an allocated string. It may not be the shortest answer possible, but it should be clear to most readers.

 #include  #include  void trim_str(char *s) { const size_t s_len = strlen(s); int i; for (i = 0; i < s_len; i++) { if (!isspace( (unsigned char) s[i] )) break; } if (i == s_len) { // s is an empty string or contains only space characters s[0] = '\0'; } else { // s contains non-space characters const char *non_space_beginning = s + i; char *non_space_ending = s + s_len - 1; while ( isspace( (unsigned char) *non_space_ending ) ) non_space_ending--; size_t trimmed_s_len = non_space_ending - non_space_beginning + 1; if (s != non_space_beginning) { // Non-space characters exist in the beginning of s memmove(s, non_space_beginning, trimmed_s_len); } s[trimmed_s_len] = '\0'; } } 
 char* strtrim(char* const str) { if (str != nullptr) { char const* begin{ str }; while (std::isspace(*begin)) { ++begin; } auto end{ begin }; auto scout{ begin }; while (*scout != '\0') { if (!std::isspace(*scout++)) { end = scout; } } auto /* std::ptrdiff_t */ const length{ end - begin }; if (begin != str) { std::memmove(str, begin, length); } str[length] = '\0'; } return str; } 

Here is a function to do what you want. It should take care of degenerate cases where the string is all whitespace. You must pass in an output buffer and the length of the buffer, which means that you have to pass in a buffer that you allocate.

 void str_trim(char *output, const char *text, int32 max_len) { int32 i, j, length; length = strlen(text); if (max_len < 0) { max_len = length + 1; } for (i=0; i=0; j--) { if ( (text[j] != ' ') && (text[j] != '\t') && (text[j] != '\n') && (text[j] != '\r')) { break; } } length = j + 1 - i; strncpy(output, text + i, length); output[length] = 0; } 

The if statements in the loops can probably be replaced with isspace(text[i]) or isspace(text[j]) to make the lines a little easier to read. I think that I had them set this way because there were some characters that I didn’t want to test for, but it looks like I’m covering all whitespace now 🙂