Re: Something wrong in my program

From: Dominique Léger (dleger_at_vif.com)
Date: 01/17/04


Date: Fri, 16 Jan 2004 18:51:45 -0500

Bruno Desthuilliers wrote:

> Dominique Léger wrote:
>> Hello guys,
>>
>> I'm kinda new to C, and I'm having a hard time with strings. What I'm
>> trying to do is a simple function that trims spaces & tabs at the
>> beginning of a
>> given string. For example, I want this: " Hello World" to become this:
>> "Hello World". At first glance, my function seems to work, but returns
>> some strange values...
>>
>> Here's my code (please pardon the mess):
>>
>> #include <stdio.h>
>> #include <string.h>
>>
>> int main(void){
>> char *trimbegin(char *text);
>
> Move the function definition above the main(), and you won't have to
> declare its prototype here.
>
>> char *str = " Hello World!";
>> char *result = trimbegin(str);
>> printf("What the function returns: \"%s\"\n", result);
>> return 0;
>> }
>>
>> char *trimbegin(char *text){
>> int i = 0, j = 0, ok = 0;
>> int size = strlen(text);
> should be a size_t, not an int.
>
>> char buffer[size + 1];
> gcc -Wall -ansi -pedantic :
> warning: ISO C89 forbids variable-size array `buffer'
>
>
>> char *ptr;
>>
>> printf("Original text is: \"%s\"\n", text);
>> printf("That's %d characters long...\n", size);
>> printf("Now, our text buffer can contain %d characters\n", size +
>> 1);
>> for (i = 0; i <= size; i++){
>> if (ok == 1){
>> buffer[j] = text[i];
>> j++;
>> }
>> else if (isspace(text[i]) == 0 && ok == 0){
> gcc -Wall -ansi -pedantic :
> warning: implicit declaration of function `isspace'
>
>> buffer[j] = text[i];
>> j++;
>> ok = 1;
>> }
>> }
>
> Are you sure your algorithm is ok and as simple as it could be ?
>
>> printf("What the result is supposed to be: \"%s\"\n", buffer);
>> ptr = buffer;
>> return ptr;
>
> Which can be shortened to :
> return &buffer[0];
> and further to :
> return buffer;
>
> in which case you've got an additionnal, and very annoying warning :
>
> gcc -Wall -ansi -pedantic :
> warning: function returns address of local variable
>
>> }
>
> You understand that, even if the value returned is an effective memory
> address, what becomes of the memory block starting at this address is no
> more under your control as soon as the function returns ? This memory
> may be reclaimed and reused by the system at any time, so trying to read
> at this at address may have any unpredictable result - not talking about
> *writing* at this address.
>
>> And here's the output:
>>
>> [dom@localhost C]$ ./a.out
>> Original text is: " Hello World!"
>> That's 14 characters long...
>> Now, our text buffer can contain 15 characters
>> What the result is supposed to be: "Hello World!"
>> What the function returns: "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿"
>>
>>
>> Why does it return "Hello World! @8@$÷ÿ¿¸öÿ¿PS@ý@Èöÿ¿" and not "Hello
>> World!"?
>
> First you forgot to copy the terminating '\0' to buffer, so buffer is
> char array, but not a string. In C, a string is a char array *terminated
> by the char '\0'*. Note that this character is *not* counted by
> strlen(), since it's not part of the string, but merely a 'sentinel'
> indicating where the string ends (the 'effective' string may be shorter
> than the memory block it is contained in).
>
> Then, you return the address of a local automatic variable, which
> invokes UB (Undefined Behavior) as soon as you read or write at this
> address. Anything can happen, even that it *seems* to work correctly.
>
> Solutions are :
> - either dynamically allocate memory for buffer in trimbegin(), or
> declare buffer outside trimbegin() and pass its address to trimbegin
> (for now you'd better try the second solution)
> - make sure that buffer terminates with a '\0' (the simplest way to do
> it being to copy the terminating '\0' of the source string)
> - eventually rewrite your algorithm to make it simpler
>
> tip 1 : you dont need any test in the for loop body nor the ok flag
> tip 2 : the for loop syntax is :
> for (<initialisation>;<test>;<on_each_iteration>)
> {
> <body>
> }
> where any of <initialisation>, <test>, <on_each_iteration>, and
> <body> can be empty.
>
>
> Feel free to post amended code for review !-)
>
> HTH
> Bruno

Here's the amended code:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

char *trim(const char *text);
int main(void){
        char *result = trim(" Hello World!");
        printf("What the function returns: \"%s\"\n", result);
        return 0;
}

char *trim(const char *text){
        int i = 0;
        static char buffer[20];
        while( isspace(text[i]) ) i++;
        strcpy(buffer, &text[i]);
        printf("What the result is supposed to be: \"%s\"\n", buffer);
        return buffer;
}

A little better, isn't it? :-) However, dynamically allocating memory for
'buffer' would definitely be more interesting. I'll try to figure it out on
my own and post the results later...

I have one last question: Everybody here seems to despise the new standard,
C99. Why is that so?

-Dom



Relevant Pages

  • Re: Discovering variable types...
    ... >- but I suppose MS expect us to use wrappers ... memory allocations for your variables from disk as well. ... >They most certainly are of fixed size, changing the size of a String ... >>me to keep buffer size and current postion right in the memory block. ...
    (comp.lang.pascal.delphi.misc)
  • Re: Cannot return values of char variable
    ... - buffer = ... Since you seem to be trying to return a char pointer ... int id = random; ... content is interpreted as a string. ...
    (comp.lang.c)
  • Re: why I can not write to the file after initialize the MFC in a service program
    ... you don't use char, an obsolete data type ... Why do you need an intermedate buffer to write literal strings anyway? ... For example, if AfxWinInit fails, you copy a 45-character string into a ... So you are going to try to initialize MFC EACH TIME THROUGH THE LOOP? ...
    (microsoft.public.vc.mfc)
  • Re: why I can not write to the file after initialize the MFC in a service program
    ... you don't use char, an obsolete data type ... Why do you need an intermedate buffer to write literal strings anyway? ... For example, if AfxWinInit fails, you copy a 45-character string into a ... So you are going to try to initialize MFC EACH TIME THROUGH THE LOOP? ...
    (microsoft.public.vc.mfc)
  • Re: Segmentation fault
    ... Here you ask for a pointer to char. ... to a random position in memory. ... There's nothing else than a string the user could enter;-) ... to the use of scanf(). ...
    (comp.lang.c)