Thread: Repeat program in C

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

    Repeat program in C

    Hi, I tried to write a C program which duplicates the content of a string. For example I typed "3 Test" and it should come out like this: "TestTestTest".

    But for me it comes out "3 Test 3 Test 3 Test". I think I have to split the string str at the position of the first space. And convert the first part into a number. I don't know if this is ok. Can someone help me to fix my code?

    Code:
    #include<stdio.h>
    #include<conio.h>
    #include<string.h>
    
    
    char* repeat(char *s,int n)
    {
    char *c;
    char *e;
    
    if(n==0)
    {
       return "";
    }
    
    if(n==1)
    {
       c=strcpy(c,s);
       return c;
    }
    
    if(n>1)
    {
    
    e=repeat(s,n-1);
    
    e=strcat(e,s);
    return e;
    }
    
    }
    
    
    void main()
    {
       char str[]="3 Test ";
       char *b;
       b= repeat(str,3);
       printf("%s",b);
    
    
    getch();
    
    }

  2. #2
    Registered User
    Join Date
    Sep 2020
    Posts
    150
    I rather would do it like this:
    Code:
    #ifdef _MSC_VER
      #define _CRT_SECURE_NO_WARNINGS
    #endif
    
    #include <stdio.h>
    #include <conio.h>
    #include <string.h>
    
    void repeat(const char* input, char *output)
    {
      int n = 0;
      char buffer[32] = {'\0'};
    
    
      if (sscanf(input, "%d %31s", &n, buffer) == 2)
      {
        // your logic to write buffer n times to output
      }
    }
    
    int main()
    {
      char input[] = "3 Test";
      char output[32] = "";
    
      repeat(input, output);
      puts(output);
    
      (void)_getch();
    }
    Last edited by thmm; 01-28-2021 at 06:54 AM.

  3. #3
    Registered User
    Join Date
    Nov 2020
    Posts
    31
    I have tried another try, but i get this error: error: invalid opeands to binary * ( have #long long unsigned int' and 'char')


    Code:
    #ifdef _MSC_VER
      #define _CRT_SECURE_NO_WARNINGS
    #endif
    
    #include <stdio.h>
    #include <conio.h>
    #include <string.h>
    
    void repeat(const char* input, char *output)
    {
      int n = 0;
      char buffer[32] = {'\0'};
    
    
      if (sscanf(input, "%d %31s", &n, buffer) == 2)
      {
    
        // your logic to write buffer n times to output
    
        {
        char *result = malloc(sizeof(input) * output + 1);
    
        while (output > 0) {
            strcat(result, input);
            output --;
        }
    
        return result;
    }
      }
    }
    
    int main()
    {
      char input[] = "3 Test";
      char output[32] = "";
    
      repeat(input, output);
      puts(output);
    
      (void)_getch();
    }

  4. #4
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,106
    Even commenting out the Widows stuff so it can be compiled under Linux:
    Code:
    #ifdef _MSC_VER
    #define _CRT_SECURE_NO_WARNINGS
    #endif
    
    #include <stdio.h>
    //#include <conio.h>
    #include <string.h>
    
    void repeat(const char* input, char *output)
    {
       int n = 0;com foo.c
       char buffer[32] = {'\0'};
    
    
       if (sscanf(input, "%d %31s", &n, buffer) == 2)
       {
    
          // your logic to write buffer n times to output
    
          // { Useless brace
          char *result = malloc(sizeof(input) * output + 1);
    
          while (output > 0) {
             strcat(result, input);
             output --;
          }
    
          return result; // Can't return a value from a "void" function
          // } And the matching
       }
    }
    
    int main()
    {
       char input[] = "3 Test";
       char output[32] = "";
    
       repeat(input, output);
       puts(output);
    
       //  (void)_getch();
    }
    It won't even compile:

    Code:
    foo.c: In function ‘repeat’:
    foo.c:21:22: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
       21 |       char *result = malloc(sizeof(input) * output + 1);
          |                      ^~~~~~
    foo.c:21:22: warning: incompatible implicit declaration of built-in function ‘malloc’
    foo.c:8:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
        7 | #include <string.h>
      +++ |+#include <stdlib.h>
        8 | 
    foo.c:21:43: error: invalid operands to binary * (have ‘long unsigned int’ and ‘char *’)
       21 |       char *result = malloc(sizeof(input) * output + 1);
          |                                           ^
    foo.c:23:21: warning: ordered comparison of pointer with integer zero [-Wpedantic]
       23 |       while (output > 0) {
          |                     ^
    foo.c:28:14: warning: ‘return’ with a value, in function returning void [-Wreturn-type]
       28 |       return result; // Can't return a value from a "void" function
          |              ^~~~~~
    foo.c:9:6: note: declared here
        9 | void repeat(const char* input, char *output)
          |      ^~~~~~
    Correct the errors first.

    Don't use conio.h and you do not free the allocated memory.

  5. #5
    null pointer Structure's Avatar
    Join Date
    May 2019
    Posts
    338

    Post

    "3 Test" and it should come out like this: "TestTestTest".
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define stringSize 512
    
    void loopText( char *inputString );
    
    int main( int argc, char *argv[] ) {
    
      loopText( "3 Test" ) ;
    
      return 0 ;
    }
    
    void loopText( char *inputString ) {
      
      int loopAmount = 0, draw = 0, count = 0 ;
      char amountString[32], textString[stringSize] ;
    
      for (int i = 0; i < (strlen(inputString)+1); i++ ) {
        if ( inputString[i] == ' ' && draw == 0 ) {
            draw = 1 ; count = 0 ; continue ;
        }
        if ( draw == 1 ) textString[count++] = inputString[i] ;
        if ( draw == 0 ) amountString[count++] = inputString[i] ;
      }
    
      loopAmount = atoi(amountString) ;
      for (int i = 0; i < loopAmount; i++) {
          printf( "%s", textString ) ;
      }
    
    }
    "without goto we would be wtf'd"

  6. #6
    Registered User
    Join Date
    Nov 2020
    Posts
    31
    Thanks, very nice

  7. #7
    Registered User
    Join Date
    Sep 2020
    Posts
    150
    That was my idea:
    Code:
    #include <stdio.h>#include <string.h>
    
    
    void repeat(const char* input, char *output)
    {
      int n = 0;
      char buffer[32] = {'\0'};
    
    
      if (sscanf(input, "%d %31s", &n, buffer) == 2)
      {
        for (int i = 0; i < n; ++i)
          strcat(output, buffer);
      }
    }
    
    
    int main()
    {
      char input[] = "3 Test";
      char output[16] = "";
    
    
      repeat(input, output);
      puts(output);
    
    
    }

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Structure View Post
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define stringSize 512
    
    void loopText( char *inputString );
    
    int main( int argc, char *argv[] ) {
    
      loopText( "3 Test" ) ;
    
      return 0 ;
    }
    
    void loopText( char *inputString ) {
      
      int loopAmount = 0, draw = 0, count = 0 ;
      char amountString[32], textString[stringSize] ;
    
      for (int i = 0; i < (strlen(inputString)+1); i++ ) {
        if ( inputString[i] == ' ' && draw == 0 ) {
            draw = 1 ; count = 0 ; continue ;
        }
        if ( draw == 1 ) textString[count++] = inputString[i] ;
        if ( draw == 0 ) amountString[count++] = inputString[i] ;
      }
    
      loopAmount = atoi(amountString) ;
      for (int i = 0; i < loopAmount; i++) {
          printf( "%s", textString ) ;
      }
    
    }
    This looks unnecessary complex to me though: you're basically using a state machine to determine if you're processing the amount string or if you're processing the text string, but as there can only be one valid state change, separating the loop into two loops would likely be more straightforward. More importantly, the code is vulnerable to buffer overflow since it fails to check that count does not exceed 31 for the amount string and stringSize - 1 for the text string. Actually, it also fails to null terminate the amount string, but you may have gotten lucky, e.g., perhaps the array was sufficiently zero initialised even though you did not do so explicitly, or since atoi just tries to parse as much as it can, it may have ignored possible junk after the valid portion of the numeric string.

    Quote Originally Posted by thmm
    That was my idea:
    This is still vulnerable to buffer overflow though: repeat does not provide a parameter for specifying the size/max length of the destination array/output string, and thus in the loop that calls strcat, it does not (as it cannot) check that strcat will not write beyond the bounds of the destination array. A lesser issue is that it unnecessarily limits the base string to a maximum length of 31, and another lesser issue is that the use of strcat in a loop in this way can be slow since strcat has to keep finding the end of the current output string.

    I might suggest an approach using dynamic memory allocation instead:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char *repeat(const char *expr)
    {
        char *base_str = NULL;
        size_t num = (size_t)strtoul(expr, &base_str, 10);
        if (expr == base_str || base_str[0] != ' ')
        {
            return NULL;
        }
        ++base_str;
    
        size_t len = strlen(base_str);
        char *result = malloc(num * len + 1);
        if (!result)
        {
            return NULL;
        }
    
        if (num == 0)
        {
            result[0] = '\0';
        }
        else
        {
            for (size_t i = 0; i < num; ++i)
            {
                strcpy(result + i * len, base_str);
            }
        }
        return result;
    }
    In a way this is a more complex approach since the caller will need to deal with calling free(), but then it imposes fewer limits on the string lengths, and arguably allows the core repeat loop to remain simple while avoiding buffer overflow by computing the result string length.

    To test:
    Code:
    size_t test_repeat(const char *expr, const char *expected)
    {
        char *result = repeat(expr);
        size_t pass = 0;
        if (expected)
        {
            if (!result)
            {
                printf("Failure: expected '%s' but received null pointer\n", expected);
            }
            else if (strcmp(result, expected) != 0)
            {
                printf("Failure: expected '%s' but received '%s'\n", expected, result);
            }
            else
            {
                pass = 1;
            }
        }
        else if (result)
        {
            printf("Failure: expected null pointer but received '%s'\n", result);
        }
        else
        {
            pass = 1;
        }
        free(result);
        return pass;
    }
    
    int main()
    {
        size_t passes = 0;
        passes += test_repeat("3 Test", "TestTestTest");
        passes += test_repeat("10 123", "123123123123123123123123123123");
        passes += test_repeat("4 hey Jude ", "hey Jude hey Jude hey Jude hey Jude ");
        passes += test_repeat("0 hello", "");
        passes += test_repeat("123 ", "");
        passes += test_repeat("5", NULL);
        passes += test_repeat("-1 hello", NULL);
        passes += test_repeat("hey Jude", NULL);
        passes += test_repeat(" hey Jude", NULL);
        passes += test_repeat("", NULL);
        printf("%zu tests passed.\n", passes);
        return 0;
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    null pointer Structure's Avatar
    Join Date
    May 2019
    Posts
    338

    Thumbs up

    fewer limits on the string lengths, and arguably allows the core repeat loop to remain simple while avoiding buffer overflow

    Repeat program in C-elegant-jpg

    "without goto we would be wtf'd"

  10. #10
    Registered User
    Join Date
    Dec 2020
    Posts
    1
    Just tried this one - works just fine

    Code:
    // goal I typed "3 Tes-" and
    // it should come out like 
    // this: "TestTestTest"
    // date: 02-02-2121
    
    #include<stdio.h>
    #include<conio.h>
    #include<string.h>
    
    char pp(char str)
    {
        char temp=' ';
    
        if(str=='3')
        {
        temp=str;
        }
        if(str=='T')
        {
        temp=' ';
        }
        if(str=='e')
        {
        temp=' ';
        }
        if(str=='s')
        {
        temp=' ';
        }
        if(str=='-')
        {
        temp=' ';
        }
        if(str=='\0')
        {
        temp=str;
        }
    
    return(temp);
    }
    
    
    char p(char str)
    {
        char temp=' ';
    
        if(str=='T')
        {
        temp=str;
        }
        if(str=='e')
        {
        temp=str;
        }
        if(str=='s')
        {
        temp=str;
        }
        if(str=='-')
        {
        temp=str;
        }
        if(str=='\0')
        {
        temp=str;
        }
    
    return(temp);
    }
    
    char main()
    {
    
        int n=0, nn=0, m=0, mm=0;
    
        char str[10]= "3   Tes- \0";
    
        char c[10],a[10],cc[10],aa[10];
    
        // beginning sorting out
        while(1)
        {
        // sort out the number as follows    
        cc[m]=pp(str[m]);
        if(cc[m]==' ')
        {
        m=m+1;
        }
        else
        {aa[mm]=cc[m];
        mm=mm+1;
        m=m+1;
        }
    
        // sort out the symbols as follows
        c[n]=p(str[n]);
        if(c[n]==' ')
        {
        n=n+1;
        }
        else
        {a[nn]=c[n];
        nn=nn+1;
        n=n+1;
        }
    
        if(n==10 || m==0)
        {    
        n=0;
        m=0;
        break;
        }    
        }
        // end sorting out
    
        printf("\nstring letters :%s:", a);
        printf("\nstring number  :%s:\n", aa);
    
        if(aa == aa)
        while(1)
        {
        printf("%s", a);    
        n=n+1;
        if(n == 3)
        {
        n=0;    
        break;
        }    
        }
    return 0;    
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Repeat C program and output scores
    By Eve Wein in forum C Programming
    Replies: 3
    Last Post: 11-20-2020, 01:42 AM
  2. Can't get my program to repeat until 0 is entered
    By Nick Ryder in forum C Programming
    Replies: 4
    Last Post: 03-18-2017, 08:43 PM
  3. How to repeat program in C
    By i6472 in forum C Programming
    Replies: 2
    Last Post: 04-01-2010, 05:59 PM
  4. repeat
    By linuxdude in forum C Programming
    Replies: 4
    Last Post: 03-28-2003, 09:40 AM
  5. repeat number program
    By nicolobj in forum C Programming
    Replies: 4
    Last Post: 10-03-2002, 10:50 PM

Tags for this Thread