LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-17-2009, 02:22 PM   #1
charlitos
Member
 
Registered: Feb 2009
Posts: 51

Rep: Reputation: 16
Question how do I change a string size dinamicly(C)


Hi, I was wondering

if I have something like

char str2[] = "string";

and then I pass it to a function which is waiting for a char * and this function wants to take this string and fill it up with more characters making it twice as big, but first I would put the values from str2 in a temporary variable using strcpy then get this values back to str2 combined some other characters.

Whats the best way to manage memory when you want to manipulate strings this way on C?
 
Old 02-17-2009, 02:49 PM   #2
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Two ways:
  • #define some max string length and then make sure not to ever write beyond that length. It is easier to prevent that by using strncpy() (and the like) instead of strcpy() all the time.
  • Calculate the total new length and allocate that much +1 byte of memory for it with malloc().

Also, IIRC, writing to a string initialized like this:
Code:
char str2[] = "string";
Is not accepted by all compilers. (if someone knows I'm wrong or knows more details, please correct me in this)
 
Old 02-17-2009, 03:09 PM   #3
raconteur
Member
 
Registered: Dec 2007
Location: Slightly left of center
Distribution: slackware
Posts: 276
Blog Entries: 2

Rep: Reputation: 44
Quote:
Originally Posted by Hko View Post
Two ways:
  • #define some max string length and then make sure not to ever write beyond that length. It is easier to prevent that by using strncpy() (and the like) instead of strcpy() all the time.
  • Calculate the total new length and allocate that much +1 byte of memory for it with malloc().

Also, IIRC, writing to a string initialized like this:
Code:
char str2[] = "string";
Is not accepted by all compilers. (if someone knows I'm wrong or knows more details, please correct me in this)
AFAIK all compilers accept unbounded string array syntax as shown in the OP's post.

I agree that using an initialized unbounded array in a case where one knows that the contents will change is a questionable practice.

Instead of a max string length approach as described above, one can always malloc() the array for the initial contents, and realloc() as necessary, with the caveats that the existing string array contents will be invalid and the pointer address will most likely change.
 
Old 02-17-2009, 03:37 PM   #4
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
I said that because I vaguely remember some command line option for gcc like "-fwritable_constants" or so, to make the compiler accpet this sort of things. But I can't find it in the man page. So I remember this wronly, or it was for ealier versions of gcc or so.

Anyway, it does not look quite "right" IMHO. At least no for strings (character arrays).
 
Old 02-17-2009, 04:58 PM   #5
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

You're both right, on all counts. Here's a snippet that illustrates:
Code:
#include <stdio.h>
#include <string.h>

#define MAX_LEN 80

char *string1 = "potentially constant";
char string2[] = "potentially constant";

int
main (int argc, char *argv[])
{
  char string3[MAX_LEN] = "definitely variable";

  fprintf (stderr, "Overwriting variable string (%s)...\n", string3);
  strcpy (string3, "ABC");
  fprintf (stderr, "New value (%s)...\n", string3);

  fprintf (stderr, "Overwriting variable string (%s)...\n", string2);
  strcpy (string2, "ABC");
  fprintf (stderr, "We might crash before we see (%s)...\n", string2);

  fprintf (stderr, "Overwriting constant string (%s)...\n", string1);
  strcpy (string1, "ABC");
  fprintf (stderr, "We might crash before we see (%s)...\n", string1);

  return 0;
}
Sample Output:
Quote:
Overwriting variable string (definitely variable)...
New value (ABC)...
Overwriting variable string (potentially constant)...
We might crash before we see (ABC)...
Overwriting constant string (potentially constant)...
Segmentation fault
PS:
FYI, the "fprintf (stderr)" thing is to make sure we see our "printf()", just in case we do crash....

PPS:
The real moral of the story, of course, is "don't do it unless you're sure it's correct!".

In this case: since we didn't explicitly allocate string1 or string2, we must not assume that we can write to them. Since we *did* allocate string3 (s[MAX_LEN]), we *can* modify it. But we can *only* modify MAX_LEN-1 characters (we must consider the null terminator, too!)

HTH .. PSM

Last edited by paulsm4; 02-18-2009 at 09:31 AM.
 
Old 02-17-2009, 05:46 PM   #6
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
paulsm4 hits the nail on the head.

What follows isn't precisely what charlitos was asking about, but there are ways you can get the compiler to help you avoid difficulty.

Segment violation is fine and dandy, but you can save yourself some potential embarrassment in the real world by getting the compiler to catch as many bugs as it can. All you have to do is know how to use const.

Here's a shell script I just ran. The meat of it is a C program. I'm showing the script so you can replicate it, but part of what the script does is to display the C program with line numbers, so you can follow the error messages. (Line numbers for the whole script wouldn't be quite accurate for finding errors in the C program, and we need to know exactly which line number the compiler finds offensive.)

Anyway, here's the script:
Code:
#!/bin/bash

cat > 1.c <<EOD
#include <stdio.h>

#if DECLARATION==1
void yellow_subroutine(      char       *       parameter)
#endif
#if DECLARATION==2
void yellow_subroutine(      char       * const parameter)
#endif
#if DECLARATION==3
void yellow_subroutine(      char const *       parameter)
#endif
#if DECLARATION==4
void yellow_subroutine(const char       *       parameter)
#endif
{
#if DEFINITION==1
  parameter[1]='o';
#endif
#if DEFINITION==2
  parameter++;
  parameter[0]='o';
#endif

} /* yellow_subroutine() */

int main(void)
{
  char broiled[]="tick";

  yellow_subroutine(broiled);

  broiled[1]='o';

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

  return 0;

} /* main() */
EOD
cat -n 1.c

for DECLARATION in 1 2 3 4
do
  for DEFINITION in 1 2
  do
    echo DECLARATION is $DECLARATION\; DEFINITION is $DEFINITION

    gcc -DDECLARATION=$DECLARATION -DDEFINITION=$DEFINITION -Wall 1.c -o 1

    if [ $? = 0 ]
    then
      1
    fi
  done
done
What the script does this:
  1. list the source code with line numbers; and
  2. in eight different ways, compile the code and, if the compilation is successful, run the code.
Let's look at the program, piece by piece.

Function main() does this:
  1. declare the "constant" array;
  2. call function yellow_subroutine();
  3. display the "constant" array; and
  4. exit.
Now here's where it gets a little interesting. Function yellow_subroutine() is declared in one of four ways, depending on how the program is compiled.

All those consts seem rather confusing, but the rules are simple:
  1. What is to the left of the const is the type of what is constant.
  2. What is to the right of the const is the thing that is constant.
The first declaration has no const, so we'll skip over that.

Here's the second declaration:
Code:
void yellow_subroutine(      char       * const parameter)
To the left is char *, which is pointer to char. To the right is parameter, which is (surprise!) of that type. So it's the pointer that is constant. With this declaration, one can change the characters themselves, but not the pointer that points to them.

And later, we'll see that this is exactly what happens.

Here's the third declaration:
Code:
void yellow_subroutine(      char const *       parameter)
To the left is char, which is the actual character(s). To the right is *parameter, which is (again, surprise!) of that type: *parameter is a character.

With this declaration, one cannot change the characters themselves, but one can change the pointer that points to them.

And again, we'll see that this is exactly what happens.

But what about the fourth declaration? This is what we so often see in code:
Code:
void yellow_subroutine(const char       *       parameter)
The rules break down here. In your mind, you have to slide that const to the right of the next token, and then apply the rules.

Really, there's no reason for the compiler to have to allow this fourth form, but they dumb things down for us so we can just get on with our day jobs.

A brief comment on these rules before we look at the results. You can have more than one const in the declaration if you wish, like this:
Code:
void yellow_subroutine(      char const * const parameter)
I urge you to try that variation to show yourself that neither the pointer nor the characters will be changeable.

You can even (if your situation demands) sprinkle more asterisks in there, having absolute control over what is constant and what is not:
Code:
void yellow_subroutine(char const ** const *** const * const * parameter)
But for this experiment, we'll just stick with the first four forms.

Now let's move on to the definition of that function: what the function actually does. In the first definition, we have:
Code:
  parameter[1]='o';
This line (line 17) doesn't change the pointer, only the data.

In the second definition, we have:
Code:
  parameter++;
  parameter[0]='o';
Line 20 changes the pointer, and then line 21 changes the data.

If neither the data nor the pointer is declared const, then both definitions change the same character.

Ok, let's see what happened.

When I ran this script, I got this output:
Code:
     1  #include <stdio.h>
     2
     3  #if DECLARATION==1
     4  void yellow_subroutine(      char       *       parameter)
     5  #endif
     6  #if DECLARATION==2
     7  void yellow_subroutine(      char       * const parameter)
     8  #endif
     9  #if DECLARATION==3
    10  void yellow_subroutine(      char const *       parameter)
    11  #endif
    12  #if DECLARATION==4
    13  void yellow_subroutine(const char       *       parameter)
    14  #endif
    15  {
    16  #if DEFINITION==1
    17    parameter[1]='o';
    18  #endif
    19  #if DEFINITION==2
    20    parameter++;
    21    parameter[0]='o';
    22  #endif
    23
    24  } /* yellow_subroutine() */
    25
    26  int main(void)
    27  {
    28    char broiled[]="tick";
    29
    30    yellow_subroutine(broiled);
    31
    32    printf("%s\n",broiled);
    33
    34    return 0;
    35
    36  } /* main() */
DECLARATION is 1; DEFINITION is 1
tock
DECLARATION is 1; DEFINITION is 2
tock
DECLARATION is 2; DEFINITION is 1
tock
DECLARATION is 2; DEFINITION is 2
1.c: In function 'yellow_subroutine':
1.c:20: error: increment of read-only location
DECLARATION is 3; DEFINITION is 1
1.c: In function 'yellow_subroutine':
1.c:17: error: assignment of read-only location
DECLARATION is 3; DEFINITION is 2
1.c: In function 'yellow_subroutine':
1.c:21: error: assignment of read-only location
DECLARATION is 4; DEFINITION is 1
1.c: In function 'yellow_subroutine':
1.c:17: error: assignment of read-only location
DECLARATION is 4; DEFINITION is 2
1.c: In function 'yellow_subroutine':
1.c:21: error: assignment of read-only location
I would first note quickly in passing that just as one would expect, the output for declaration 4:
Code:
void yellow_subroutine(const char       *       parameter)
is exactly the same as for declaration 3:
Code:
void yellow_subroutine(      char const *       parameter)]
So we won't worry about declaration 4 any more.

For declaration 1, which was this:
Code:
void yellow_subroutine(      char       *       parameter)
everything "worked":
Code:
DECLARATION is 1; DEFINITION is 1
tock
DECLARATION is 1; DEFINITION is 2
tock
We would expect that, because there was no const in the way.

For declaration 2, which forbade changing the pointer but allowed changing the characters:
Code:
void yellow_subroutine(      char       * const parameter)
we got this:
Code:
DECLARATION is 2; DEFINITION is 1
tock
DECLARATION is 2; DEFINITION is 2
1.c: In function 'yellow_subroutine':
1.c:20: error: increment of read-only location
Definition 1 doesn't try to change the pointer. Definition 2 changes the pointer on line 20, and the data on line 21.

For declaration 3, which forbade changing the data but allowed changing the pointer:
Code:
void yellow_subroutine(      char const *       parameter)
we got this:
Code:
DECLARATION is 3; DEFINITION is 1
1.c: In function 'yellow_subroutine':
1.c:17: error: assignment of read-only location
DECLARATION is 3; DEFINITION is 2
1.c: In function 'yellow_subroutine':
1.c:21: error: assignment of read-only location
Definition 1 changes the data on line 17, and definition 2 changes the data on line 21. Both fail at compile time. But definition 2 also changes the pointer on line 20, and this works.
 
Old 02-17-2009, 05:47 PM   #7
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
So, it's the difference between char *str and char str[].
Thanks for clarifying that.
 
Old 02-17-2009, 05:48 PM   #8
charlitos
Member
 
Registered: Feb 2009
Posts: 51

Original Poster
Rep: Reputation: 16
ok, im getting to understand this so far. Now here is other question about the same concept. If I loop through a string that reserved a size of 100 in memory but it only contains 20 character and the null character. What would happen if I try to put 25 new characters into this string looping through it character by character and making changes in this way:

Code:
mystring[i] = 'r';
do I have to put the null character myself when im done? will the compiler automatically put this character for me?

Last edited by charlitos; 02-17-2009 at 05:50 PM.
 
Old 02-17-2009, 05:48 PM   #9
Biddle
Member
 
Registered: Jan 2009
Posts: 37

Rep: Reputation: 17
Sorry paulsm4 but that is a good example of why not to try things in a compiler to see if it is valid, instead of reading the standard.
 
Old 02-17-2009, 05:56 PM   #10
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Quote:
Originally Posted by Biddle View Post
Sorry paulsm4 but that is a good example of why not to try things in a compiler to see if it is valid, instead of reading the standard.
It did answer my question clearly though..
 
Old 02-17-2009, 06:00 PM   #11
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Thanks wje_lq for the in depth info.
I understand it except for:
Code:
void yellow_subroutine(char const ** const *** const * const * parameter)
What the heck does this mean?
 
Old 02-17-2009, 06:07 PM   #12
Biddle
Member
 
Registered: Jan 2009
Posts: 37

Rep: Reputation: 17
Quote:
Originally Posted by Hko View Post
It did answer my question clearly though..
Quote:
...just in case we do crash..
Ok. So now do you know if it is defined behaviour to write to the memory in string1 and string2?
 
Old 02-17-2009, 06:20 PM   #13
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
do I have to put the null character myself when im done?
Yes.
 
Old 02-17-2009, 06:27 PM   #14
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: FreeBSD,Debian wheezy
Posts: 811

Rep: Reputation: 179Reputation: 179
Quote:
Originally Posted by Hko View Post
Thanks wje_lq for the in depth info.
I understand it except for:
Code:
void yellow_subroutine(char const ** const *** const * const * parameter)
What the heck does this mean?
Code:
void yellow_subroutine(char const ** const *** const * const * parameter)
                                  76       543       2       1
It means:
  1. pointer (changeable) to
  2. pointer (unchangeable) to
  3. pointer (unchangeable) to
  4. pointer (changeable) to
  5. pointer (changeable) to
  6. pointer (unchangeable) to
  7. pointer (changeable) to
  8. char (unchangeable).
 
Old 02-17-2009, 06:51 PM   #15
charlitos
Member
 
Registered: Feb 2009
Posts: 51

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by wje_lq View Post
Yes.
I dont know...I tested the code without putting the null character and apparently the compiler knows where the string ends without problems at all.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
C++ vector or string size sefaklc Programming 20 08-02-2008 12:14 AM
Trying to change String using sed with a string \/home\/user\/Desktop icecoolcorey Programming 10 06-12-2008 11:32 PM
How do i change the size of a xterm window or lanch one with a specified size? Garavix Linux - Newbie 2 04-20-2006 09:06 PM
Really strange change of string values in C realos Programming 34 08-08-2005 09:32 PM
reading a char string of variable size in C introuble Programming 3 05-08-2005 01:07 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:02 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration