0

Ok, I know this will probably be flagged as a duplicate, but I've searched everywhere and not been able to figure this out, so please bear with me.

Let me start off by saying that this is for a homework assignment, so I cannot change the function parameter types.

Also, I am not allowed to use any libraries (well, inside the function that does the changing).

Part 1


First, how would I accomplish this:
void changeMe(char* s, int size) {
   //Change s to be "Hello, World!"
}

int main(void) {
   char* c;
   changeMe(c, 13);
   printf("%s", c); //Print out "Hello, World!"
}

(The homework doesn't call for the "Hello, World!" bit, but I don't need help with the logic, just changing the passed variable.)

I have looked all over, and most answers end up like this one here, which says that I need the parameter to be char** s, or char*& s in order to change it.

Is my only choice to assume that enough memory is already allocated to s before it is passed? For example:

void changeMe(char* s, int size) {
   int i;
   for (i = 0; i < size - 1; i++) s[i] = 'a';
   s[size - 1] = '\0';
}

int main(void) {
   char* c = (char*) malloc(10 * sizeof(char)) ;
   changeMe(c, 10);
   printf("%s", c); //Prints out "aaaaaaaaa"
}

This works fine, but removing the malloc(...) from the declaration of c doesn't.

Putting malloc(...) inside of the changeMe(...) function works locally, but only lasts as long as changeMe is in scope.

Is there a way to change my char* c without assuming it has enough memory allocated to it before it is passed to the function?

Part 2


This pretty much falls right into the same exact category as what is above, so I will do a bit less explaining here.

The function:

void split(char* s, char** sub, int max, char sep) {
   //Split string s by sep char, store all substrings found into sub
   //sub will have at most max substrings in it.
}

I am not asking for help writing the logic of finding and splitting up char* s by char c. I can do that. My issue is primarily the same as above. How do I allocate memory to char** sub so that it can fit all of the substrings in it (and, of course, change the variable passed).

For example:

void split(char* s, char** sub, int max, char sep) {
   //-->(Needed) Make sub able to hold max strings.
   //(Not Needed) Logic for splitting s up by sep, creating a substring.
   //-->(Needed) Making sub[i] have memory to hold current substring.
}

int main(void) {
   char* s = "Some String To Use";
   char** subs;
   split(s, subs, 10, ' ');
   //subs should look like this:
   //{"Some", "String", "To", "Use"}
}

I don't need help doing the actual work, I am just confused as to how to pass subs into split(...) and have it allocate the appropriate memory and change subs.

Fin


If you have made it this far through my question, thank you for reading.

And, before all of the "did you try google" comments come in, yes. Here some of what I have looked at so far:

(Edit: Thanks, haccks, for adding hyperlinks for me.)

Again, if I was writing this for myself, I would change the parameters (char** s instead of char* s for example), and use nice, useful functions like strcpy, etc, but I cannot do that in this case. Any help/input would be very appreciated, thank you all so much in advance!

Community
  • 1
  • 1
Steven Jeffries
  • 3,522
  • 2
  • 20
  • 35
  • given that you must change the contents of parameter (char *), this must be preallocated and then you can use [sprintf](http://www.cplusplus.com/reference/cstdio/sprintf/) or similar to write (change) into the (char *) object – amdixon Nov 14 '13 at 08:08
  • That is what I'm hoping is the case, because that is the only way I can think of doing this. I am still confused on the sub** part though. – Steven Jeffries Nov 14 '13 at 08:15
  • 1. Not without changing the caller side to provide a valid buffer, or the receiver side to accept a pointer-to-pointer (or in C++ a reference-to-pointer). – WhozCraig Nov 14 '13 at 08:18

4 Answers4

1

Part 1

The whole point of the size parameter is for the function changeMe() to know the size of the buffer. You do not need to assume the size as, typically, such a function would be used as follows:

int main()
{
    int size;
    char* c;

    // some code to calculate the required size of the buffer in bytes
    size = calculateRequiredSize();

    // allocate the buffer
    c = ( char* )malloc( size );

    changeMe( c, size );
}

However, in response to your question, in the function changeMe() there is no way to change the data stored in the buffer without assuming that a memory buffer of size bytes has already been allocated.

Part 2

The same logic goes in here, although it is split (pun intended) in 2 parts.

Simply modifying your example, you would do the following:

void split(char* s, char** sub, int max, char sep) {

    char*   pCurrent;   // pointer to the beginning of the current substring inside the original string.
    int     lenCurrent; // length of the current substring

    // Making sub[i] have memory to hold current substring.
    int i;
    for ( i = 0; i < max; ++i )
    {
        //(Not Needed) Logic for splitting s up by sep, creating a substring.
        // OK -> I leave it to you.

        sub[i] = (char *)malloc( lenCurrent + 1 );  // use length of the current substring + an extra space for the terminating NULL character

        // I will leave it to you to copy the substring to sub[i]
    }
}

int main(void) {
    char* s = "Some String To Use";
    int max = 10; // Decide the value of max out here.
    char** subs = (char**)malloc( max * sizeof( char* ) );
    // Make subs able to hold max strings.
    split(s, subs, max, ' ');
    //subs should look like this:
    //{"Some", "String", "To", "Use"}
}
ajcaruana
  • 505
  • 3
  • 14
  • He said that he is not allowed to use any library calls in the function, so I think `malloc` in the split() function is forbidden... – ElyashivLavi Nov 14 '13 at 08:25
  • I am pretty sure I cannot use malloc, but I think I am allowed to change the input string, so I can do as ElyashivLavi suggested, and change the occurrences of the separating token to '\0' and have subs[i] point to their respective place. Thank you, ajcaruana, for your extremely helpful input. – Steven Jeffries Nov 14 '13 at 08:54
0

Good luck with your homework! Att least you were honest enough to admit you are doing homework here... :)

Regards Part 2:

Sub is actually an array of char* - (char *sub[max]).

So you need to go over s, find where to split and what is the size of the splitted part. After that, allocate the needed size in the sub[] array. In this way, you will allocate exactly the amount you need.

Another solution: In case you are not allowed to use malloc(), you can change *s string. Go over it, and change every occurrence of sep to '\0'. Then point the correct sub[i] pointer to the beginning of the string. This is actually how strsep() works.

Demonstartion:

Let's say that s is "Hello-World-This-Is-Homework". Then set sub[0] to point to s[0], which is the beginning of the first part. The go over s until the next '-'. Change it to '\0'. Then point s[1] to the beginning of "World", and change the next '-' to '\0', etc...

Regards Part 1:

After you've told us that in part 2 you received an already-allocated array, I assume that in part 1 the array is also already allocated. So you actually have char s[size]. So it seems that your solution is correct - if the user passed wrong element in size, this is his fault. You cannot verify it.

ElyashivLavi
  • 1,681
  • 3
  • 22
  • 33
  • I would up-vote if I could (not enough reputation). I think I am going to assume that there is already memory allocated, and, as you suggest, change each sub[i] to point to a location in the string. Thank you so much for your input! – Steven Jeffries Nov 14 '13 at 08:51
0

When you modify an array (pointer) passed as a parameter to a function, you modify it's content in caller too. That's because C works by copying parameters, but in this case it copies the pointer, not the value it points to. So, you need to modify the value that pointer points to in your function, without having to pass the pointer in a special way. But, note that in order to be able to access and modify the memory, it has to be allocated in the caller function. That is why you can not remove malloc.

Paul92
  • 8,827
  • 1
  • 23
  • 37
  • Judging from all of the answers and everything I've read, I think it is safe to assume that my functions will be supplied with parameters that already have memory allocated to them. Thanks for helping clarify that for me. – Steven Jeffries Nov 14 '13 at 09:01
0

part 1

if your function prototype changeMe(char* s, int size) cannot be changed then your only option is to provide the function with a buffer that is large enough to accommodate your new string,

void changeMe( char* s, int size )
{
  if ( s != NULL && s > 0 )
  {
    char* p = strncpy( s, "Hello, World", size-1 ); // assuming size includes \0
    if ( p != NULL )
    {
      p[size - 1] = '\0'; // make sure it is 0 terminated.
    }
  }
}

the reason why you need "char** s" as a parameter to change the size is that char* s means that the address is passed to the function by value i.e. a copy of the original address similar to if you would have passed say an int:

void foo(int n) // n is a copy of the original value
{
  n = 1; // modifying the copy
}

the value of n would not change outside foo but if you write

void foo(int* n) // n is now pointing to the original value
{
  *n = 1; // changing what n points to i.e. the original value
}  

when it comes to strings it is the same principle just with one more level of indirection

void foo(char* s)
{
  s = "hello"; // just temporarily changes what the copy s points to, not the original
}

void foo(char** s)
{
  *s = malloc(10); // changes what the original s points to
}

Part 2

Hint: look at realloc(), that function works as malloc but expands the memory block dynamically

AndersK
  • 35,813
  • 6
  • 60
  • 86
  • Thank you for the answer. Unfortunately, I am not allowed to use any library functions inside my changeMe and split functions, so malloc and realloc are off the table (and, unfortunately, strcpy). However, your answer was very informative and did help clarify things for me. Thanks for the response. – Steven Jeffries Nov 14 '13 at 08:58