fork download
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <assert.h>
  6. #include <ctype.h>
  7.  
  8. // Had to adjust macros a bit.
  9.  
  10. char *String_Utils_concat(char *string_one, char *string_two, int parameter);
  11. char *String_Utils_set(char **string_one, char *string_two, int parameter);
  12. char *String_Utils_copy(char *string, int parameter);
  13. void testString_Utils_concat();
  14.  
  15. #define NONE 1 << 0
  16. #define MODIFY 1 << 1
  17. #define DEBUG 1
  18. #define DEBUG_PRINTF(MESSAGE, ...)(DEBUG ? fprintf(stderr, MESSAGE, __VA_ARGS__) : DEBUG)
  19. #define VALIDATE_PTR(PTR, RETURN_VAL) do { if(PTR == NULL){ \
  20.   DEBUG_PRINTF("Error: %s == NULL\n", #PTR); return RETURN_VAL;}} while(0)
  21. #define SELECTED(ARGUMENT, MACRO)((ARGUMENT & MACRO))
  22.  
  23.  
  24. char *String_Utils_concat(char *string_one, char *string_two, int parameter) { // For this demonstration, MODIFY is passed
  25. char *temp = NULL;
  26. // Validate_PTR checks if pointer is null, and if so returns the second parameter, I.E NULL
  27. VALIDATE_PTR(string_one, NULL);
  28. VALIDATE_PTR(string_two, NULL);
  29. // Allocate temporary string to size of two strings, + 1 for null terminator
  30. temp = malloc(strlen(string_one) + strlen(string_two) + 1);
  31. // Zeroes the struct to clean it.
  32. memset(temp, 0, strlen(string_one) + strlen(string_two) + 1);
  33. // Copies the first string to temp
  34. strcpy(temp, string_one);
  35. // Concatenates string_two to temp
  36. strcat(temp, string_two);
  37. // Based on parameters below, will modify the original screen, or just return the new string.
  38. if (SELECTED(parameter, MODIFY)) {
  39. String_Utils_set(&string_one, temp, NONE); // The call to set. Passes address of the string
  40. // Free temp as no longer needed.
  41. free(temp);
  42. return string_one; // Has to return something, may as well be the same string
  43. } else return temp; // Not modifying the original string is the default, even if there was no valid parameter.
  44. }
  45.  
  46. char *String_Utils_set(char **string_one, char *string_two, int parameter) {
  47. VALIDATE_PTR(string_one, NULL);
  48. VALIDATE_PTR(*string_one, NULL); // Also checks if the string is null through the reference.
  49. VALIDATE_PTR(string_two, NULL);
  50. printf("Value of *string_one = %s\nMemory Address of *String_one = %p\n String_two = %s\n", *string_one, *string_one, string_two);
  51. char *temp_string_two = String_Utils_copy(string_two, parameter); // Copy returns a copy of the string modified with the parameter
  52. // Frees the string. This WILL SEGFAULT if a normal string literal was passed.
  53. free(*string_one);
  54. *string_one = malloc(strlen(temp_string_two) + 1); // Allocates string_one.
  55. // Clears out the string
  56. memset(*string_one, 0 , strlen(temp_string_two)+1);
  57. // Copy string_two into string_one
  58. strcpy(*string_one, temp_string_two);
  59. free(temp_string_two);
  60. printf("Final result of *String_one = %s\nFinal Memory Address of *String_one = %p\n", *string_one, *string_one);
  61. return *string_one;
  62. }
  63.  
  64. char *String_Utils_copy(char *string, int parameter) { // Returns a copy of the string modified if parameters are passed.
  65. VALIDATE_PTR(string, NULL);
  66. // Allocates a temporary string to hold copy of string
  67. char *temp = malloc(strlen(string) + 1);
  68. strcpy(temp, string);
  69. // The below will modify temp the appropriate parameter.
  70. //if(SELECTED(parameter, LOWERCASE)) temp = String_Utils_to_lowercase(temp, MODIFY); // MODIFY parameter always results in calling set.
  71. //if(SELECTED(parameter, UPPERCASE)) temp = String_Utils_to_uppercase(temp, MODIFY); // Comment these out if you want to run without it.
  72. //if(SELECTED(parameter, REVERSE)) temp = String_Utils_reverse(temp, MODIFY);
  73. return temp;
  74. }
  75.  
  76. // The test portion
  77.  
  78. void testString_Utils_concat() {
  79. char* string_one = "Hello ";
  80. char* string_two = "World";
  81. char *string_three = String_Utils_copy("", NONE); // In order to change this value, a copy of the string is returned else SEGFAULT
  82. printf("\n\n\nString_Three's value: %s\nString_Three's memory address: %p\n", string_three, string_three);
  83. char *null_string = NULL;
  84. int parameter_one = NONE;
  85. int parameter_two = MODIFY;
  86. char* result_one = String_Utils_concat(string_one, string_two, parameter_one);
  87. char *result_two = String_Utils_concat(string_one, null_string, parameter_one);
  88. String_Utils_concat(string_three, result_one, parameter_two); // Modifies string_three
  89. printf("String_Three's value: %s\nString_Three's memory address: %p\n", string_three, string_three);
  90.  
  91. if (strcmp(result_one, "Hello World") != 0) {
  92. //assert(0);
  93. }
  94. if(result_two != NULL) assert(0);
  95. if(strcmp(result_one, string_three) != 0) assert(0);
  96. printf("Passed test: Concat!\n");
  97. //free(string_one);
  98. //free(string_two);
  99. free(string_three);
  100. free(result_one);
  101. free(result_two);
  102. }
  103.  
  104. int main(void){
  105. testString_Utils_concat();
  106. return 0;
  107. }
Success #stdin #stdout #stderr 0s 2140KB
stdin
Standard input is empty
stdout


String_Three's value: 
String_Three's memory address: 0x9157008
Value of *string_one = 
Memory Address of *String_one = 0x9157008
 String_two = Hello World
Final result of *String_one = Hello World
Final Memory Address of *String_one = 0x9157008
String_Three's value: Hello World
String_Three's memory address: 0x9157008
Passed test: Concat!
stderr
Error: string_two == NULL