Thread: A string from a different function

  1. #1
    Registered User
    Join Date
    Nov 2020
    Posts
    14

    A string from a different function

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void changeString(char *str);
    int main(){
         char *string;
         string = (char *)malloc(5 * sizeof(char));
         changeString(string);
         printf("\nNew string is %s\n",string);
         free(string);
         return 1;
    }
    void changeString(char *str){
          char *name;
          int ptr=0;
    
          name = (char *)malloc(sizeof(char)*5);
          do{
             scanf("%c", &name[ptr]);
             ptr++;
             if(ptr == 5){
                  name = (char *)realloc(name, 10 * sizeof(char));
             }
             
          }while(name[ptr-1] != '\n');
          str = (char *)realloc(str, sizeof(char) * ptr);
          strcpy(str,name);
          free(name);
    }
    What's the output of printf?
    When i run the program it works properly, but with valgrind it doesnt.

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    You cast the result of malloc! WRONG!
    You fail to check for realloc failing! BAD IDEA!

    You seem to have never ran your program! LAZY!

    You use ptr to mean index!

    You fail to allocate space for the trailing zero byte or understand the trailing zero byte is needed!

    Tim S.
    Last edited by stahta01; 05-11-2021 at 07:30 AM.
    "...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

  3. #3
    Registered User
    Join Date
    Apr 2021
    Posts
    139
    When you pass a value as an argument to a C function, it is passed "by value". That is, a byte-for-byte copy of the value of the argument is placed on the call stack or in a register, where the function is free to do whatever it wants, including modifying that value.

    However, any changes to the value are not copied back to the caller. There is no provision in C for any kind of "update" to a value to propagate from a called function back to its caller.

    This is why we use pointers. With a pointer, you can call "by reference." The calling function puts the address of a modifiable object onto the stack (or in a register) as an argument to the function. The callee (the function) takes the address, uses the address to modify the value stored, and then returns. After which, the calling function can see the updates that have been made.

    In your code, you attempt to use the realloc() function to change the size of the memory block pointed to by the parameter str. The realloc() function is documented as having three possible behaviors:

    1. It changes the size of the referenced memory block, leaving the pointer unchanged but increasing the space available.
    2. It allocates a new memory block of sufficient size, copies the contents, and returns a differently-valued pointer to the new memory block.
    3. It fails to allocate and returns null.

    Your code does not allow for case 2 or case 3. You call realloc, and assign the resulting value to str. But str is a parameter, and parameters don't get copied back to the caller, so any change to str will be lost. The only time your code can work is case 1.

    Note: This explains why your code doesn't work with valgrind. Most memory allocators will return blocks aligned to either 8 or 16 bytes. Meaning that they almost certainly allocate in chunks at least that big. If your system's malloc is 16-byte aligned, that probably explains why you can get a realloc from 5 to 10 bytes with no problem. Using valgrind turns on some safety checks, which likely makes realloc always return a new block.

    In order to get your code to work for case 3, you simply have to check for null and then print a message and die.

    In order to get your code to work for case 2, you need to either (a) pass the string parameter by reference (using a pointer) instead of by value; or (b) return the new value from your function, and update the string in main.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Like this perhaps.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char *changeString(char *str, size_t size);
    
    int main()
    {
      char *string;
      string = malloc(5 * sizeof(*string));
      string = changeString(string, 5);
      printf("\nNew string is >>%s<<\n", string);
      free(string);
    
      // you can even start with no initial allocation
      string = changeString(NULL,0);
      printf("\nNew string is >>%s<<\n", string);
      free(string);
    
      return 0;
    }
    
    char *changeString(char *str, size_t size)
    {
      size_t pos = 0;
      do {
        if ((pos+1) >= size) {  // allow for the \0
          size_t new_size = size + 10;
          void *t = realloc(str, new_size * sizeof(*str));
          if (t) {
            str = t;
            size = new_size;
          } else {
            // realloc failed, return what we have
            return str;
          }
        }
        if ( scanf("%c", &str[pos]) == EOF ) {
          str[pos] = '\0';
          return str; // user got bored
        }
        pos++;
        // always keep the result a valid \0 terminated string
        str[pos] = '\0';
      } while (str[pos - 1] != '\n');
      return str;
    }
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 01-15-2012, 06:09 AM
  2. Replies: 5
    Last Post: 10-24-2011, 12:35 PM
  3. Replies: 2
    Last Post: 05-19-2008, 10:42 PM
  4. Replies: 9
    Last Post: 04-16-2007, 03:02 PM
  5. Replies: 4
    Last Post: 01-22-2002, 11:13 PM

Tags for this Thread