Copy pointer to pointer in function - C

Pages: 12
Jan 28, 2021 at 8:39pm
Hello,

I'd like to copy pointer to pointer in function and I don't want to use the library. But in main I have the old string instead a new string.

Thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26


int Insert(char* Str1, char* Str2, int n)
{
	
	stringCopy(Str3, Str1, n);
	stringCopy(Str3, Str2, lenS2);
	stringCopy(Str3, Str1 + n, lenS1 -lenS2);

	Str1 = Str3; // Pointer assignment is OK but in main function, I have old string..

	return 1;
}


int main()
{

	char* Str1 = "Blahblahblah";
	char* Str2 = "123";
	Insert(Str1, Str2, 4);

	printf_s("%s\n", Str1); // I have old string instead new string

	return 0;
}
Jan 28, 2021 at 9:04pm
Line 10 is just overwriting Str1, which is a local variable. If you need to change a pointer in main, you need two levels of indirection to change the pointer within another function.

i.e.
1
2
3
4
5
void foo(type **var)
{
    // ...
    *var = something_else;
}


But I don't understand your code, since I'm not sure what Str3 is or what it's pointing to.

If you're trying to re-implement strcat, just pass a char array buffer and a pointer to a c-string.
Last edited on Jan 28, 2021 at 9:12pm
Jan 28, 2021 at 9:08pm
Thank you for your answer,
But I can't change the signature of the function.

Str3 is:

char* Str3 = (char*)malloc(lenS1 + lenS2 + 2);
Jan 28, 2021 at 9:28pm
Changing the value of Str1 itself will have no effect outside the local function. It's the same thing as if Str1 were an int. Assigning var = 42; will have no effect outside the local function.

So is Str3 a global variable? That's the only way out of this mess, as you have it. print Str3, not Str1. Otherwise, as you currently have it, what you're doing doesn't make sense to me.

PS, just because I'm bored, I made a modified version of strcat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>

int my_strlen(const char* str)
{
    int n;
    for (n = 0; *(str++); n++);
    return n;
}

void concat(char* buffer, const char* str, int n)
{
    int len = my_strlen(buffer);
    int append_len = my_strlen(str);
    int i;
    for (i = 0; i < append_len + 1 && i + len < n; i++)
    {
        buffer[i + len] = str[i];
    }
    buffer[n-1] = '\0';
}

int main()
{
    char output[10] = "First";
    concat(output, "Second", 10);

    printf("%s\n", output);

    return 0;
}
Last edited on Jan 28, 2021 at 11:43pm
Jan 29, 2021 at 2:09am
how is the return value used? pointers are just integers...
you could return it in the return value, 0 (null in C) for errors etc, as another way out.

then it would just be
newstr = insert(blah blah). I don't think you even have to cast it, in C, do you? I think its friendly to cast it anyway but C people get bent out of shape over unnecessary casting.
Last edited on Jan 29, 2021 at 2:10am
Jan 29, 2021 at 10:12am
just because I'm bored, I made a modified version of strcat.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void strcatn(char* buffer, const char* str, size_t n)
{
	char* end = buffer + n - 1;

	while (*buffer++);

	for (--buffer; buffer < end && (*buffer++ = *str++); );
	*buffer = '\0';
}

int main()
{
	char output[10] = "First";

	strcatn(output, "Second", 10);
	puts(output);

	return 0;
}

Jan 29, 2021 at 10:21am
Thank you, @Ganado, but your code is wrong.
Jan 29, 2021 at 10:22am
This is my code, I shouldn't change the signature of Insert method. I want to return Str1 as a new string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<stdio.h>
#include<stdlib.h>

int lengthOfString(char* Str1)
{
	int i, length = 0;
	for (i = 0; Str1[i] != '\0'; i++)
	{
		length++;
	}

	return length;
}

void stringCopy(char* Str3, char* Str1, int x)
{
	int lenStr3 = lengthOfString(Str3);
	int j = 0;
	for (int i = lenStr3; i < lenStr3 + x; i++)
	{
		Str3[i] = Str1[j];
		j++;
	}
	Str3[lenStr3 + x] = '\0';

}

int Insert(char* Str1, char* Str2, int n)
{
	int lenS2 = lengthOfString(Str2);
	int lenS1 = lengthOfString(Str1);

	if (lenS2 == 0 || lenS1 == '\0')
		return -1;
	if (lenS1 < n)
		return -1;
	char* Str3 = (char*)malloc(lenS1 + lenS2 + 2);
	Str3[0] = '\0';
	stringCopy(Str3, Str1, n);
	stringCopy(Str3, Str2, lenS2);
	stringCopy(Str3, Str1 + n, lenS1 - lenS2);

	Str1 = Str3;

	return 1;
}

int main()
{

	char* Str1 = "Blahblahblah";
	char* Str2 = "123";
	Insert(Str1, Str2, 4);

	printf_s("%s\n", Str1);

	return 0;
}
Jan 29, 2021 at 10:28am
The memory allocated to Str3 is not freed - there's a memory leak.

What is the given desc/spec for insert() - what is it supposed to do?
Jan 29, 2021 at 10:36am
Thank you @seeplus, but your code doesn't change the output string.

https://i.ibb.co/9sTfL8x/Screenshot-2021-01-29-053344.jpg
Jan 29, 2021 at 10:38am
Thank you @seeplus,

It's string concatenation at a specific position. for example: Str1 should be "Blah123blahblah" after executing the method.

char* Str1 = "Blahblahblah";
char* Str2 = "123";
Insert(Str1, Str2, 4);
Jan 29, 2021 at 10:41am
1
2
3
4
5
6
7
8
9
int main()
{
	char output[20] = "blahblahblah";

	strcatn(output, "123", 20);
	puts(output);

	return 0;
}


does.


blahblahblah123


I ask again - what is insert() supposed to do?
Jan 29, 2021 at 10:43am
OK I understand now.......
Jan 29, 2021 at 10:52am
1
2
3
char* Str1 = "Blahblahblah";
char* Str2 = "123";
Insert(Str1, Str2, 4); 


That should fail as Str1 doesn't have space for the insertion. You should have:

1
2
char Str1[20] = "blahblahblah";
Insert(Str1, "123", 4, 20);


with the extra param for the size of the buffer.

If you don't then you are changing the address to which Str1 points and expect the calling program to know this and free the memory - which is not good. Instead, rather than insert() returning an int, have it return a char* pointing to the new string.
Jan 29, 2021 at 11:05am
Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>

void strcatn(char* buffer, const char* str, size_t n)
{
	char* end = buffer + n - 1;

	while (*buffer++);

	for (--buffer; buffer < end && (*buffer++ = *str++); );
	*buffer = '\0';
}

size_t lenstr(const char* str)
{
	const char* beg = str;

	for (; *str; ++str);

	return str - beg;
}

char* insert(const char* str1, const char* str2, size_t n)
{
	size_t l1 = lenstr(str1);
	size_t l2 = lenstr(str2);

	char* buffer = (char*)calloc(l1 + l2 + 1, 1);

	strcatn(buffer, str1, n + 1);
	strcatn(buffer, str2, l2 + n + 1);
	strcatn(buffer, str1 + n, l1 + l2 + 1);
	return buffer;
}

int main()
{
	const char* const str1 = "blahblahblah";

	char* out = insert(str1, "123", 4);

	puts(out);
	free(out);

	return 0;
}



blah123blahblah


Jan 29, 2021 at 11:14am
Thank you @seeplus, but I shouldn't change the signature of method.

int Insert(char* Str1, char* Str2, int n)
Jan 29, 2021 at 11:22am
The address pointed to by Str1 can't be changed by Insert(). As you are not passing as an argument the size of the Str1 buffer, this means that it has to be assumed that the memory pointed to by Str1 is large enough to contain the final string - which is dangerous for buffer overflow issues.

Who devised this function definition - it's bad design!
Jan 29, 2021 at 11:29am
Consider then (not good - potential buffer overflow!):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>

void strcatn(char* buffer, const char* str, size_t n)
{
	char* end = buffer + n - 1;

	while (*buffer++);

	for (--buffer; buffer < end && (*buffer++ = *str++); );
	*buffer = '\0';
}

size_t lenstr(const char* str)
{
	const char* beg = str;

	for (; *str; ++str);

	return str - beg;
}

int insert(char* str1, const char* str2, size_t n)
{
	size_t l1 = lenstr(str1);
	size_t l2 = lenstr(str2);

	if (l2 == 0 || l1 == 0 || l1 < n)
		return -1;

	char* buffer = (char*)calloc(l1 + l2 + 1, 1);

	strcatn(buffer, str1, n + 1);
	strcatn(buffer, str2, l2 + n + 1);
	strcatn(buffer, str1 + n, l1 + l2 + 1);
	*str1 = 0;
	strcatn(str1, buffer, l1 + l2 + 1);

	free(buffer);
	return 1;
}

int main()
{
	char str1[20] = "blahblahblah";

	insert(str1, "123", 4);
	puts(str1);

	return 0;
}

Last edited on Jan 29, 2021 at 11:31am
Jan 29, 2021 at 1:32pm
For a version not using strcatn, consider (with the same caveats):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
size_t lenstr(const char* str)
{
	const char* beg = str;

	for (; *str; ++str);

	return str - beg;
}

int insert(char* str1, const char* str2, size_t n)
{
	size_t l1 = lenstr(str1), l2 = lenstr(str2);

	if (l2 == 0 || l1 == 0 || l1 < n)
		return -1;

	char *buffer = (char*)calloc(l1 + l2 + 1, 1), *bufbeg = buffer, *org = str1;

	for (size_t i = 0; i < n && (*buffer++ = *str1++); ++i);
	while (*buffer++ = *str2++);
	for (--buffer; *buffer++ = *str1++; );
	for (str1 = org, buffer = bufbeg; *str1++ = *buffer++; );

	free(bufbeg);
	return 1;
}

Jan 29, 2021 at 2:08pm
Ah right, this whole time I wasn't considering making str1 itself point to an actual buffer and not just read-only memory. That would work and I think meet OP's reqs.

Edit:
Thank you, @Ganado, but your code is wrong.
Maybe English isn't your first language, so you are speaking incorrectly. My code being "wrong" means something different than my code not meeting your specific needs. If my code is wrong, tell me how it's wrong. The buffer being size 10 was intentional as a test.
Last edited on Jan 31, 2021 at 3:55pm
Pages: 12