Reputation: 603
EDIT: I added the full code.
I get an array with names and need them to create a string, depending of how many names exist this string looks different. I tried to concatenate the strings with strcpy and strcat but it doesn't work.
char* function1 (size_t n, const char *const names[n]) {
char *res;
switch (n) {
case 0:
res = "no one likes this";
break;
case 1:
strcpy(res, names[0]);
strcat(res, " likes this");
break;
case 2:
strcpy(res, names[0]);
strcat(res, " and ");
strcat(res, names[1]);
strcat(res, " like this");
break;
case 3:
strcpy(res, names[0]);
strcat(res, ", ");
strcat(res, names[1]);
strcat(res, " and ");
strcat(res, names[2]);
strcat(res, " like this");
break;
default:
strcpy(res, names[0]);
strcat(res, ", ");
strcat(res, names[1]);
strcat(res, " and ");
strcat(res, (char*) (n - 2));
strcat(res, " others like this");
break;
}
return res;
}
How can I get the names from the array? Do I have to get the length of each name and then copy each char by char?
The function is called as follow:
int main(void) {
const char *const names[3] = {"John", "Peter", "Paul"};
char* res = function1(3, names);
printf("%s", res);
return 0;
}
The result should be as follows:
I know how to concat the strings, but struggling to copy the names out of the array. This is from a C exercise in a tutorial.
Upvotes: 0
Views: 1829
Reputation: 141165
char *res = "";
strcpy(res,
Such code is invalid and it is undefined behavior. String literals like "string"
but also just ""
are immutable. You can't write to them. And because language is very old, it allows you to do char *res = ""
, while it should only allow to do const char *res = ""
like in c++.
To copy the strings somewhere, you have have that "somewhere" - a block of free memory that will have enough space to hold the result.
How can I get the names from the array?
Iterate over the array and "get the names".
void function1 (size_t n, const char *const names[n]) {
for (size_t i = 0; i < n; ++i) {
printf("Getting names[%zu]=%s\n", i, names[i]);
}
}
Do I have to get the length of each name and then copy each char by char?
If you want to concatenate those strings together, then you have to copy them char by char. Also include space for a separator, for example a space.
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
char *function1(size_t n, const char * const names[n]) {
// Calculate how much space we need
// for zero sentinel value and...
size_t len = 1;
// ...and for all the names and...
for (size_t i = 0; i < n; ++i) {
len += strlen(names[i]);
}
// ...and for space in between words.
if (n != 0) {
len += n - 1;
}
// Allocate memory. sizeof(*res) = sizeof(char) = 1
char *res = malloc(len * sizeof(*res));
if (res == NULL) {
// always handle errors
return NULL;
}
// Initialize with empty string.
res[0] = '\0';
for (size_t i = 0; i < n; ++i) {
// Concatenate the names.
strcat(res, names[i]);
if (i + 1 != n) {
// And remember about separating them.
strcat(res, " ");
}
}
return res;
}
int main(void) {
const char * const names[3] = {"John", "Peter", "Paul"};
char* res = function1(3, names);
if (res == NULL) {
return EXIT_FAILURE;
}
printf("Names concatenated with space as separator: %s\n",
res);
free(res);
}
Upvotes: 1
Reputation: 153547
Code fails various cases as res
is not initialized before use.
char *res;
...
// res value is indeterminate. Result: undefined behavior.
// v
strcpy(res, names[0]); // bad code
Instead code needs to set res
to point to valid memory area before strcpy(res, ...)
.
Usual idea would be to calculate memory needs, allocate memory and then assign.
To avoid repetitive work, code could use a variable length array (VLA) to save the lengths of the names.
Find all the lengths, add them up, allocate and concatenate.
OP is also looking for some special text between names
. Leave that for OP to add.
// void function1 (size_t n, const char *const names[n]) {
char *function1 (size_t n, const char *const names[n]) {
size_t length[n]; // VLA
size_t total = 0;
for (size_t i=0; i<n; i++) {
length[i] = strlen(names[i])
total += length[i];
}
char *all = malloc(total + 1);
if (all) {
size_t offset = 0;
for (size_t i=0; i<n; i++) {
memcpy(&all[offset], names[i], length[i]);
offset += length[i];
}
all[offset] = '\0';
}
return all;
}
Upvotes: 1
Reputation: 67546
It has to be done like this
char *function1 (size_t pos, const char ** names) {
char *res = malloc(strlen(names[pos])+1);
strcpy(res, names[0]);
/*....*/
return res;
}
Your code has so many issues in two lines of code ...\
char res[] = "";
<- wrong)char res[strlen(name[pos])+1];
<- wrong)void function1 (size_t pos, const char ** names, char **res) {
*res = malloc(strlen(names[pos])+1);
strcpy(*res, names[0]);
/*....*/
}
Upvotes: 0
Reputation: 319
From man strcpy
:
The strcpy() function copies the string pointed to by src, including the
terminating null byte ('\0'), to the buffer pointed to by dest. The strings may
not overlap, and the destination string dest must be large enough to receive the
copy
The last line suggests you to allocate enough space for the string to be copied so you will inevitably have to calculate it's length.
Upvotes: 0