Thread: return string should work, but ..

  1. #1
    Registered User
    Join Date
    Mar 2017
    Posts
    22

    return string should work, but ..

    Hello,

    i am new to C, but know some basic and z80source
    i try to make a decimal-string from any 8bit value, so string from 3 chars + \0
    it all works, but i always have the wrong type of 'return' value
    if it realy works, i remove all those printstatements.
    version 038 by now:
    Code:
    #include <stdio.h>
    
    char * strint(int num ) {
    /* avoiding other libs , keeping it simple */
    
    if (num >255) return ;  /* set 8bit maximum */
    
    char str[3] ;  /* '255'  needs 3 char spaces */
    
    int s ;
    
    for (s=0 ; s<3 ; s++) str[s]=' ' ;
    str[3]='\0';
    
    printf("1-%d..%s..\n",num, str);
    
    str[0] = num /100 ;
    printf("2-%c..\n",str[0]+48);
    
    num = num -100* str[0];
    str[0]=str[0]+48  ; /*ascii*/
    printf("3-%d..%s..\n",num, str);
    
    str[1] = num/10 ;
    printf("4-%c..\n",str[1]+48);
    
    num = num -10* str[1];
    str[1]=str[1]+48  ; /*ascii*/
    printf("5-%d..%s..\n",num, str);
    
    str[2]=num;
    printf("6-%c..\n",str[2]+48);
    str[2]=str[2]+48  ; /*ascii*/
    printf("7-%d..%s..\n",num, str);
    
     return  *str ;
      
    }
    
    void main() {
      printf( "the number is: %c \n" , strint(213) ) ;
    }
    
    result:
    ch@linux-4xd4:~/Downloads/fuse-1.3.3> ./strint_038
    1-213..   ..
    2-2..
    3-13..2  ..
    4-1..
    5-3..21 ..
    6-3..
    7-3..213..
    the number is: 2
    printf( "the number is: %s \n" , strint(213) ) ;

    gives
    1-213.. ..
    2-2..
    3-13..2 ..
    4-1..
    5-3..21 ..
    6-3..
    7-3..213..
    Segmentation fault

    but it is a string, it should be,
    what do i mis here?
    i guess its simple, hope so anyway

    Chris
    Last edited by CBorn; 04-26-2017 at 02:36 PM.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Can anyone actually read this post?
    I can't see it at all.
    This has happened before.
    What's going on?

  3. #3
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,111
    Not me either. Don't know how it got posted.

    Some database error?

  4. #4
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Quote Originally Posted by algorism View Post
    Can anyone actually read this post?
    I can't see it at all.
    This has happened before.
    What's going on?
    I can read this post; but, it is the only one in the thread.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  5. #5
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    If you hover over the title on the C Programming forum page, you can see the following, which is presumably the first part of what should be the first post:
    Hello,

    i am new to C, but know some basic and z80zource
    i try to make a decimal-string from any 8bit value, so string from 3 chars + \0
    it all works, but i always have the wrong type of 'return' value
    if it realy works, i remove all those printstatements.
    version 038 by now:

    #include...

  6. #6
    Registered User
    Join Date
    Mar 2017
    Posts
    22
    Hello,
    its "my" tread. i reported it to the webmaster.
    i noticed that the text is indeed visible in the "mouse-over-text"
    I was editing THIS tread and maybe pressed in the wrong TAB of my browser on "back" or some a like
    dont know

    my question was and is about the 'return' values

    Code:
    #include <stdio.h>
    
    char * strint(int num ) {
    /* avoiding other libs , keeping it simple */
    if (num >255) return NULL ;  /* set 8bit maximum */
    
    char str[3] ;  /* '255'  needs 3 char spaces */
    int s, dv ;
    
    dv=100;
    for (s=0 ; s<3 ; s++) {
    str[s] = num /dv ;
    num = num -dv* str[s];
    str[s]=str[s]+48  ; /*ascii*/
    dv= dv/10 ;
    }
    str[s]='\0';
    
    printf("%d..%s",s, str);    /* with out this printf-statement there is only garbage  is it printf that does the job ?? */
    
    return str ;
    }
    
    void main() {
     /*  char str[3]; */
      printf( "the number is: %s \n" , strint(213) ) ;
    }
    result :
    Code:
    ch@linux-4xd4:~/Downloads/fuse-1.3.3> gcc strint_078.c -ansi -g -o strint_078
    strint_078.c: In function ‘strint’:
    strint_078.c:22:1: warning: function returns address of local variable [-Wreturn-local-addr]
     return str ;
     ^
    ch@linux-4xd4:~/Downloads/fuse-1.3.3>
    i want to use it in a bigger programme were i try to learn by expanding the tape-browser, of fuse-emulator , Fuse - the Free Unix Spectrum Emulator download | SourceForge.net

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > with out this printf-statement there is only garbage
    Because
    > warning: function returns address of local variable

    The compiler isn't lying.
    If you return a pointer to a local variable, the variable goes out of scope with the return.
    By going out of scope, the associated memory is free to be used by something else instead.


    A crude way to fix the problem is to make the memory static, like so
    Code:
    char * strint(int num ) {
    /* avoiding other libs , keeping it simple */
    if (num >255) return NULL ;  /* set 8bit maximum */
    
    static char str[4] ;  /* '255\0'  needs 4 char spaces */
    ...
    But this has the problem that you can only call the function serially.
    This would work.
    printf( "the number is: %s \n" , strint(213) ) ;
    This wouldn't.
    printf( "the numbers are: %s %s \n" , strint(213) , strint(42) ) ;


    A better way (say like sprintf) is to pass the buffer you want to store the string in.
    Code:
    char * strint(int num, char *str) {
    ...
        return str;
    }
    
    int main ( ) {
      char buff[4];
      printf( "the number is: %s \n" , strint(213,buff) ) ;
    }

    > char str[3] ; /* '255' needs 3 char spaces */
    Except you always put a \0 on the end, so you really need 4 characters.



    Also, enable as many warnings as possible.
    Code:
    $ gcc -Wall -Wextra foo.c
    foo.c: In function ‘strint’:
    foo.c:21:8: warning: function returns address of local variable [-Wreturn-local-addr]
     return str ;
            ^
    foo.c: At top level:
    foo.c:24:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
     void main() {
          ^
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Mar 2017
    Posts
    22
    Quote Originally Posted by Salem View Post
    > with out this printf-statement there is only garbage
    Because
    > warning: function returns address of local variable
    so its the same problem. aha.

    By going out of scope, the associated memory is free to be used by something else instead.
    like that printstatement aperently...

    [/code]
    But this has the problem that you can only call the function serially.
    This would work.
    printf( "the number is: %s \n" , strint(213) ) ;
    This wouldn't.
    printf( "the numbers are: %s %s \n" , strint(213) , strint(42) ) ;
    the realy crazy part which made me backoff for years...
    some times i feel like the pingpingBAL being battered by error codes....

    > char str[3] ; /* '255' needs 3 char spaces */
    Except you always put a \0 on the end, so you really need 4 characters.
    i thoughed byte 0 is the first one so [3] should give 4 char spaces. 0,1,2,3.

    Also, enable as many warnings as possible.
    Code:
    $ gcc -Wall -Wextra foo.c
    foo.c: In function ‘strint’:
    foo.c:21:8: warning: function returns address of local variable [-Wreturn-local-addr]
     return str ;
            ^
    foo.c: At top level:
    foo.c:24:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
     void main() {
          ^
    That one is a big help aswell.
    I was doubting the difference between the messages while compiling fuse-emulator with gcc in terminal and compiling this file in kate giving gcc a 'silent' command with the build-plugin

    Thank you Salem.
    so i go 'static'

  9. #9
    Registered User
    Join Date
    Mar 2017
    Posts
    22

    Talking

    the last and working version

    Code:
    #include <stdio.h>
    
    char * strint(int num ) {
    /* avoiding other libs , keeping it simple */
    
    static char str[3] ;  /* '255'  needs 3 char spaces */
    str[3]='\0';  
    
    if (num <0 || num >255) { str[0]='n'; str[1]='o'; str[2]='p'; goto back ; } /* set 8bit maximum */
    
    int s, dv ;
    
    dv=100;
    for (s=0 ; s<3 ; s++) {
    str[s] = num /dv ;
    num -= dv * str[s];
    str[s]+= 48  ; /*ascii*/
    dv= dv/10 ;
    }
    
    back:
    return str ;
    }
    
    int main() {
      int temp ;
      printf("give any number from 0 to 255\n");
      scanf("%d", &temp);
      printf( "the number is: %s \n" , strint(temp) ) ;
    }
    Last edited by CBorn; 04-27-2017 at 07:22 AM. Reason: num <0 ||

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > the last and working version
    Nope - you still have an array overrun.

    You should fix your 'goto' with an if / else construct.

    If you wrote
    str[s]+= '0';
    you wouldn't need the comment, and you wouldn't be assuming that the world uses ascii.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    Registered User
    Join Date
    Mar 2017
    Posts
    22
    can you explain the array overrun?
    the routine is working afaik and it seems good like this since str[3]='\0' sets the terminator.
    what do i mis ??

  12. #12
    Registered User
    Join Date
    Feb 2012
    Posts
    347
    In c array indexing starts from 0. Hence if it is a[3]. You can have a[0],a[1],a[2] only and not a[3].

  13. #13
    Registered User
    Join Date
    Mar 2017
    Posts
    22
    Quote Originally Posted by Satya View Post
    In c array indexing starts from 0. Hence if it is a[3]. You can have a[0],a[1],a[2] only and not a[3].
    I counted something dubbel.
    quote"char string[50];This would declare a string with a length of 50 characters." declaring is the AMOUNT and the first is 0.
    In zx basic there is no 0-index in arrays.
    So after the remark to include 0-index, my mind made it as if [3] is the place AND amount with that automatic '\0' somewhere
    but the declaration is the amount and there is the "default 0+1 error" very much available, so to say.
    if i need 4 char, then i declare 4 char.
    and apperently the '\0' marker is not needed, since its not used, i think,. i guess,...
    but if i use a array part that does NOT exsist, then Why is it accepted?
    is it created after all ???
    Last edited by CBorn; 04-27-2017 at 01:27 PM.

  14. #14
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    In order to store a string properly you must count all of the characters you will use: you can see that "255" is 3 characters but you should always add 1 for the terminating zero ('\0'). If you fail to do that or make some other mistake with strings, the extra space required is not created for you. C is not like newer languages where arrays are checked and errors always occur.

    I will show you how an array overrun does not necessarily lead to an obvious error, since I think that is the best way to explain.

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
       struct strings_type 
       {
          char foo[5];
          char bar[6];
       } example;
    
       strcpy(example.foo, "0123456789"); /* string is deliberately too long - needs 11 */
       puts(example.foo);
       return 0;
    }
     
    0123456789
    The strcpy() function wrote into other nearby memory, bar, which is clearly wrong, but it executes just fine.

    Now this code is easy to fix by using strncpy() because that function will only copy a set number of characters into the array, but you will have to be similarly careful with how you manipulate strings.
    Last edited by whiteflags; 04-27-2017 at 03:35 PM.

  15. #15
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,111
    Quote Originally Posted by whiteflags View Post
    Now this code is easy to fix by using strncpy() because that function will only copy a set number of characters into the array, ...
    Or even better by expanding the size of the array. Unless you are programming for an embedded system, why limit yourself an array of 4 chars to hold a 3 char string, plus the Nul byte. Simply make it 10, or 20 chars. Give yourself some breathing room!

    Of course, you still have to keep in mind that ALL arrays in C are zero based. Even an array of 20 for this program, would still be accessed elements 0 through 19, NOT 1 through 20!!

    Also, please avoid "Magic Numbers" in your code! use a #define to specify the size of the array.

    For example:
    Code:
    #define DIM 10
    // ...
    char str[DIM] ;
    // ...
    for (s=0 ; s<DIM ; s++) str[s]=' ' ;
    // ...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 12-29-2015, 02:00 PM
  2. Replies: 6
    Last Post: 04-09-2006, 04:32 PM
  3. Replies: 4
    Last Post: 01-30-2006, 05:04 AM
  4. A simple return and it does not work
    By kotte in forum C++ Programming
    Replies: 4
    Last Post: 01-27-2006, 12:22 AM

Tags for this Thread