Thread: variable argument list for string concatenation

  1. #1
    Registered User
    Join Date
    Feb 2018
    Location
    San Diego, CA
    Posts
    63

    variable argument list for string concatenation

    Hey all...i've been working at this C programming since Feb 2018, currently using clang on freebsd 11.2. I am the second time through a 700 page book, only 2 more lessons left, then I hope to move onto K&R 2nd editon ANSI-C. Quick question, please give me some clues toward working on my current question & answer on Lesson 19 out the my text i'm working on....


    "write a function that is (a) passed a number of strings as arguments, (b) concentates the strings, into one longer string, and (c) returns a pointer to the new string to the calling program".

    I am familiar with:
    Code:
    int func_1(int num, ...)
    is always going to be an integer, and was confused about maybe using a char array in the function prototype. And also, i was kind of thinking to assign each string (i.e. string_1 & string_2) to an integer so I could pass it to the function like this:

    Code:
    char c;
    c = func_1(1);
    But wasn't sure how to do this. I have googled "variable argument list", understand (to an extent) how to use the macros in a program, and also have been re-reading the material in my text.

    Pseudo-code helpful. Thanks!

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,490
    Well you already know how variable arguments work, just look at how you call printf()

    Then read about va_start(), va_arg() and va_end() in stdarg.h
    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.

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    632
    What is the title of your "700 page book"?

    Passing "a number of strings" is a very loose problem description. It could mean a fixed number of strings:
    Code:
    char *concatenate1(const char *a, const char *b, const char *c);
    Or it could mean "a number of strings" passed as an array of strings, in which case you need some way to know how many strings are in the array. One way is to pass that information in:
    Code:
    char *concatenate2(const char **strs, size_t n);
    Another way to determine how many strings there are is to use a NULL pointer as the last "string":
    Code:
    char *concatenate3(const char **strs); // last "string" is a NULL pointer
    If you want to use a variable argument list, then you have the same two options to determine how many strings there are. Either pass the size as the first parameter:
    Code:
    char *concatenate4(size_t n, ...);
    Or pass one of the strings as the first parameter (functions with variable argument lists need at least one named parameter), and pass a NULL as the last "string":
    Code:
    char *concatenate5(const char *s0, ...); // last argument must be NULL
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdarg.h>
     
    char *concatenate1(const char *a, const char *b, const char *c)
    {
        char *result = malloc(strlen(a) + strlen(b) + strlen(c) + 1);
        strcpy(result, a);
        strcat(result, b);
        strcat(result, c);
        return result;
    }
     
    char *concatenate2(const char **strs, size_t n)
    {
        size_t size = 0;
        for (size_t i = 0; i < n; ++i)
            size += strlen(strs[i]);
        char *result = malloc(size + 1);
        *result = '\0';
        for (size_t i = 0; i < n; ++i)
            strcat(result, strs[i]);
        return result;
    }
     
    char *concatenate3(const char **strs)
    {
        size_t size = 0;
        for (size_t i = 0; strs[i]; ++i)
            size += strlen(strs[i]);
        char *result = malloc(size + 1);
        *result = '\0';
        for (size_t i = 0; strs[i]; ++i)
            strcat(result, strs[i]);
        return result;
    }
     
    char *concatenate4(size_t n, ...)
    {
        va_list va;
        va_start(va, n);
         
        size_t size = 0;
        for (size_t i = 0; i < n; ++i)
            size += strlen(va_arg(va, const char *));
     
        char *result = malloc(size + 1);
        *result = '\0';
     
        va_end(va);
        va_start(va, n);
     
        for (size_t i = 0; i < n; ++i)
            strcat(result, va_arg(va, const char *));
     
        va_end(va);
        return result;
    }
     
    char *concatenate5(const char *s0, ...)
    {
        if (!s0) return "";
     
        va_list va;
        va_start(va, s0);
         
        size_t size = strlen(s0);
     
        const char *s = va_arg(va, const char *);
        while (s)
        {
            size += strlen(s);
            s = va_arg(va, const char *);
        }
     
        char *result = malloc(size + 1);
     
        strcpy(result, s0);
     
        va_end(va);
        va_start(va, s0);
     
        s = va_arg(va, const char *);
        while (s)
        {
            strcat(result, s);
            s = va_arg(va, const char *);
        }
     
        va_end(va);
        return result;
    }
     
    int main()
    {
        const char *strs[] = { "one", "two", "three", "four", "five", NULL };
     
        char *s1 = concatenate1("one", "two", "three");
        char *s2 = concatenate2(strs, 5);
        char *s3 = concatenate3(strs);
        char *s4 = concatenate4(5, "one", "two", "three", "four", "five");
        char *s5 = concatenate5("one", "two", "three", "four", "five",
                                (const char*)NULL);
        // Note that the NULL should be cast to the proper type of pointer
        // since variable argument lists are untyped.
     
        printf("%s\n", s1);
        printf("%s\n", s2);
        printf("%s\n", s3);
        printf("%s\n", s4);
        printf("%s\n", s5);
     
        free(s1);
        free(s2);
        free(s3);
        free(s4);
        free(s5);
     
        return 0;
    }
    BTW, I can't make any sense out of your proposal:
    i was kind of thinking to assign each string (i.e. string_1 & string_2) to an integer so I could pass it to the function
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  4. #4
    Registered User
    Join Date
    Feb 2018
    Location
    San Diego, CA
    Posts
    63
    john.c: thanks for the lengthy post, time & effort. The book is "C Programming in One Hour a Day, Sams Teach Yourself" by Bradley L. Jones. And yes it is outdated, because the book uses gets() in the source code examples throughout the book.

    I have decided the lesson quiz, stated in the comment of my source code book, possibly is not asking to use variable argument lists for string concatenation, possibly. I will work on code, to this questions: "write a function that is (a) passed a number of strings as arguments, (b) concentrates the strings, into one longer string, and (c) returns a pointer to the new string to the calling program".

  5. #5
    Registered User
    Join Date
    Feb 2018
    Location
    San Diego, CA
    Posts
    63
    john.c: I reread your post and yes there is a variety of explanations for "passing a number of strings". I am going to work on the code now

  6. #6
    Registered User
    Join Date
    Feb 2018
    Location
    San Diego, CA
    Posts
    63
    This is what I came up with:

    Code:
    /* Write a function that (a) is passed a variable number of strings as arguments, (b) concatenates the strings, in order, into one longer string, and (c) returns a pointer to the new string to teh calling program. */
    
    #include <stdio.h>
    #include <string.h>
    
    char *my_function(char *a, char *b);
    
    int main(void)
    {
    	char *a = "jamie";
    	char *b = "string_2";
    
    	my_function(a, b);
    	
    	return 0;
    }
    
    char *my_function(char *a, char *b)
    {
    	strcat(a, b);
    	
    	printf("%s", a);
    	
    	return a;
    }

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,158
    a and b point to the first character of string literals, so you cannot modify what they point to. Unfortunately, by using strcat in that way, you are trying to modiffy what a points to, which results in undefined behaviour.
    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

  8. #8
    Registered User
    Join Date
    Feb 2018
    Location
    San Diego, CA
    Posts
    63
    /* Write a function that is (a) passed an array of any numeric data type as an argument, (b) finds the largest and smallest values in the array, and (c) returns pointers to these values to the calling program. (Hint: You need some way to tell the function how many elements are in the array.) */
    Code:
    #include <stdio.h>
    
    #define LIMIT 6
    
    int *maximum(int my_array[]);
    int *minimum(int my_array[]);
    
    int main( void )
    {
    	int balance[LIMIT] = { 2, 16, 22, 39, 76, 81 };
    
    	maximum(balance);
    	minimum(balance);
    
    	return 0;
    }
    
    int *maximum(int my_array[])
    {
    	int counter;
    	int temp;
    
    	int maximum;
    	int location = 1;
    
    	maximum = my_array[0];
    
    	for(counter = 1; counter < LIMIT; counter++)
    	{
    		if(my_array[counter] > maximum)
    		{
    			maximum = my_array[counter];
    			location = counter+1;
    		}
    
    	}
    
    	printf("Largest value: %d\n", maximum);
    
    	return 0;
    }
    
    int *minimum(int my_array[])
    {
    	int counter_2;
    	int temp_2;
    
    	int minimum;
    	int location_2 = 1;
    
    	minimum = my_array[0];
    
    	for(counter_2 = 1; counter_2 < LIMIT; counter_2++)
    	{
    		if(my_array[counter_2] < minimum)
    		{
    			minimum = my_array[counter_2];
    			location_2 = counter_2+1;
    		}
    	}
    
    	printf("Smallest value: %d\n", minimum);
    
    	return 0;
    }
    Hey all, again, worked on this...was not sure about the return values for each maximum & minimum function, but this compiles with no errors.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,490
    > (Hint: You need some way to tell the function how many elements are in the array.)
    So you need to pass the length of the array as the 2nd parameter.
    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. End of a variable argument list
    By GigaRoid in forum C++ Programming
    Replies: 38
    Last Post: 09-03-2011, 05:37 PM
  2. Variable Argument List
    By vb.bajpai in forum C Programming
    Replies: 2
    Last Post: 06-16-2007, 05:35 AM
  3. Passing Through A Variable Argument List
    By SMurf in forum C Programming
    Replies: 6
    Last Post: 04-14-2007, 11:12 AM
  4. I'll have a Variable argument list to go...
    By SMurf in forum C Programming
    Replies: 6
    Last Post: 02-27-2003, 02:02 PM
  5. variable-length argument list ???
    By null in forum C Programming
    Replies: 5
    Last Post: 10-14-2001, 03:18 PM

Tags for this Thread