Jump to content

  • Log In with Google      Sign In   
  • Create Account


[.net] changing a character in a C# string


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 athono   Members   -  Reputation: 132

Like
0Likes
Like

Posted 11 July 2011 - 01:28 PM

changing a character in a C# string



suppose I have created a string in C# and I want to change the last character to a blank.

private static string sOldMassiveOutput;

public static string oldmassiveoutput
{
get { return sOldMassiveOutput.Trim(); }
set { sOldMassiveOutput = value; }
}
oldmassiveoutput[oldmassiveoutput.Length - 1] = ' ';

This will not work.
How do I make it work?



Sponsor:

#2 SiCrane   Moderators   -  Reputation: 9158

Like
1Likes
Like

Posted 11 July 2011 - 01:36 PM

In .NET strings are immutable. You need to create a new string with the contents that you want. This can be done with dumping the string in a char array and modifying that, using a StringBuilder, using sub string and concatenation operations, etc.

#3 Moe   Crossbones+   -  Reputation: 1235

Like
0Likes
Like

Posted 11 July 2011 - 04:44 PM

String.Replace() is your friend. Also, .Trim() would automatically lop off the trailing space anyway.

#4 landlocked   Members   -  Reputation: 103

Like
-4Likes
Like

Posted 12 July 2011 - 08:20 AM

In .NET strings are immutable. You need to create a new string with the contents that you want. This can be done with dumping the string in a char array and modifying that, using a StringBuilder, using sub string and concatenation operations, etc.

Dude, way too deep here. Strings are immutable but the CLR takes care of all that stuff in the background. Unless you've got a thousand page book stored in a string and are duplicating said string several times you won't really notice anything performance wise.

Moe is right about Trim taking off the trailing space.

Remove the call to Trim() and use Remove and Insert to modify the string. These will return strings so you will have to capture the result. Simply calling s.Remove(...) won't really do anything. You'll need s = s.Remove(...) followed by s = s.Insert(...). Or in your case s would be oldmassiveoutput.
Always strive to be better than yourself.

#5 TheOrzo   Members   -  Reputation: 168

Like
0Likes
Like

Posted 12 July 2011 - 08:45 AM

Dude, way too deep here. Strings are immutable but the CLR takes care of all that stuff in the background. Unless you've got a thousand page book stored in a string and are duplicating said string several times you won't really notice anything performance wise.

There is nothing 'too deep' about understanding that strings are immutable; it's the reason you need to remember to re-assign your string after every operation (i.e. don't just call replace without using the result). I cannot count the number of times I've seen people forget to do this and wonder why their string manipulation doesn't work. Understanding the immutable nature of strings prevents making this mistake repeatedly.

Also, mentioning usage of StringBuilder is entirely appropriate considering the example given had a string named 'sOldMassiveOutput'. You don't need a thousand page book for performance to degrade quickly when performing many operations on a large string, such as building a couple large strings every frame of a game by concatenating a string by 1 character over and over.




#6 landlocked   Members   -  Reputation: 103

Like
0Likes
Like

Posted 12 July 2011 - 09:15 AM

Also, mentioning usage of StringBuilder is entirely appropriate considering the example given had a string named 'sOldMassiveOutput'. You don't need a thousand page book for performance to degrade quickly when performing many operations on a large string, such as building a couple large strings every frame of a game by concatenating a string by 1 character over and over.

I did a test one time with StringBuilder, string.Concat and + sign concatenation in loops with a million iterations. While StringBuilder was slightly faster (by mere MS) at the end of the day it really doesn't matter. This is one place where micro-optimization is fail and people worry about it too much.

Also, if you keep building the same large string over and over you are doing it wrong. DRY (don't repeat yourself) applies here perfectly. While traditionally when people talk about DRY they are speaking in reference to code but it applies to data as well. If you are constantly generating the same string over and over then you should just store the entire string somewhere and check for the proper conditions with which it should appear. If it's a template string ("You inflicted x damage to y creature.") then use the .NET formatting characters and store the template string instead ("You inflixed {0} damage to {1}") and consume said template using string.Format.
Always strive to be better than yourself.

#7 SiCrane   Moderators   -  Reputation: 9158

Like
0Likes
Like

Posted 12 July 2011 - 11:29 AM

Strings are immutable but the CLR takes care of all that stuff in the background.

OK, then show me how to modify a string without creating a new one.

#8 landlocked   Members   -  Reputation: 103

Like
-9Likes
Like

Posted 12 July 2011 - 11:34 AM


Strings are immutable but the CLR takes care of all that stuff in the background.

OK, then show me how to modify a string without creating a new one.

I didn't say you could. I said the CLR takes care of it for you and unless you're storing entire tomes in a single string object that you really won't notice a performance hit doing a few concatenations. You even quoted me saying such. STFU.
Always strive to be better than yourself.

#9 SiCrane   Moderators   -  Reputation: 9158

Like
1Likes
Like

Posted 12 July 2011 - 11:38 AM

I didn't say you could. I said the CLR takes care of it for you and unless you're storing entire tombs in a single string object that you really won't notice a performance hit doing a few concatenations. You even quoted me saying such. STFU.

No, I quoted you saying that immutability is handled in the background and that you don't need to worry about it. If you truly didn't need to think about strings being immutable you should be able to show an example of modifying a string. Since you can't do so, then the fact that strings are immutable is relevant information and not "too deep". Note that my post said absolutely nothing about performance and was about the fact that you can't modify the string and need to create a new one.

#10 landlocked   Members   -  Reputation: 103

Like
0Likes
Like

Posted 12 July 2011 - 11:41 AM

The too deep part was advising the OP to use a char[] or a StringBuilder object when it's just as performant for all intents and purposes say s = s.Replace(args). You were advocating more complexity than is necessary.
Always strive to be better than yourself.

#11 SiCrane   Moderators   -  Reputation: 9158

Like
0Likes
Like

Posted 12 July 2011 - 12:19 PM

You see, when you say the post is too deep, and your very next sentence starts with immutability and says nothing about char arrays or StringBuilder (or for that matter, the entire post says nothing about them), the connotation is that you think that understanding strings are immutable is too deep. Secondly, immutability is not handled in the background. Immutability is a core principle of the interface of the string class. If anything it's the opposite way around, strings are actually mutable in the background, but you never need to worry about it because the CLR itself is the only thing allowed to muck with them. If you want to say that char arrays and StringBuilder aren't necessary for performance then say that. Also, if those were the only options I mentioned then maybe then you could say that I was "advocating" them, but I also mentioned another option and noted that those weren't the only options.

#12 landlocked   Members   -  Reputation: 103

Like
-1Likes
Like

Posted 12 July 2011 - 12:28 PM

You see, when you say the post is too deep, and your very next sentence starts with immutability and says nothing about char arrays or StringBuilder (or for that matter, the entire post says nothing about them), the connotation is that you think that understanding strings are immutable is too deep. Secondly, immutability is not handled in the background. Immutability is a core principle of the interface of the string class. If anything it's the opposite way around, strings are actually mutable in the background, but you never need to worry about it because the CLR itself is the only thing allowed to muck with them. If you want to say that char arrays and StringBuilder aren't necessary for performance then say that. Also, if those were the only options I mentioned then maybe then you could say that I was "advocating" them, but I also mentioned another option and noted that those weren't the only options.

No. Strings are immutable. The CLR handles the string creation process, tracking memory allocation and references and collection when all references fall out of scope. "This is a string" is a string that will be entered into the CLRs string tables. Any "change" to that creates a new string. Let's say you want to "add" a period. "This is a new string." is now a fresh new string in the CLRs string tables along side the string "This is a string". As soon as all references to the first string are out of scope the CLR wipes out the string slot and waits for something else to store there.

In the following scenario there are 3 strings created and stored in the CLR:

string s = "This is a string.";
s = s.Remove(s.Length - 1);
s = s.Insert(s.Length, ' '); //insert space


However, even though three strings are created the CLR sees that after the first string is modified to remove the last character there are no more references to the string "This is a string." and wipes it out. The same is true for the .Insert line. The CLR creates the new string "This is a string " and wipes out the string "This is a new string" as there are no more references to it. The CLR never manipulates the strings themselves. In this way all strings are immutable and not even the CLR itself modifies strings. You are wrong. CLR handles immutability in that it tracks the references of string locations and as soon as there are no more references to a string it gets wiped out. Doing this you never have to worry yourself with strings themselves and can focus entirely on doing what you need to do.
Always strive to be better than yourself.

#13 SiCrane   Moderators   -  Reputation: 9158

Like
0Likes
Like

Posted 12 July 2011 - 01:24 PM

The CLR can modify strings if it likes. The prime example is the StringBuilder class implementation from .NET 2.0 to, I believe, 3.5. Internally, that implementation used a string object that got modified. (This got changed - .NET 4.0's StringBuilder uses a char array internally.) If you don't believe me, grab a copy of Reflector and point it at the .NET 2.0 StringBuilder implementation.

#14 DvDmanDT   Members   -  Reputation: 542

Like
0Likes
Like

Posted 12 July 2011 - 01:50 PM

OP:
The only way I know to modify an existing string is the following, but please note that it's a horrible idea that will most likely give you tons of headache and all sorts of unexpected problems.

string str = "Hello world";

unsafe{
    fixed(char *tmp = str)
    {
         *(tmp + str.Length - 1) = ' ';
    }
}

Console.WriteLine(str);
Console.WriteLine("Hello world");

The second WriteLine is there to show you why it's a horrible idea.

#15 Washu   Senior Moderators   -  Reputation: 3974

Like
0Likes
Like

Posted 12 July 2011 - 01:55 PM

The CLR can modify strings if it likes. The prime example is the StringBuilder class implementation from .NET 2.0 to, I believe, 3.5. Internally, that implementation used a string object that got modified. (This got changed - .NET 4.0's StringBuilder uses a char array internally.) If you don't believe me, grab a copy of Reflector and point it at the .NET 2.0 StringBuilder implementation.


Yes, specifically the .net 2.0 StringBuilder used the String class's internal function "AppendInPlace".

Frankly, landlocked, I'm not a fan of your attitude. You appear to be rather confrontational. If you have an argument to be made about a particular topic then you should elucidate your thoughts and reasons, generally backed up with references. Furthermore, this is the .Net forum, not the For Beginners forum. Therefore going in depth into the functionality and behavior of various components of the .Net such as the CLR or CLI is hardly "too deep".

OP:
The only way I know to modify an existing string is the following, but please note that it's a horrible idea that will most likely give you tons of headache and all sorts of unexpected problems.

string str = "Hello world";

unsafe{
    fixed(char *tmp = str)
    {
 		*(tmp + str.Length - 1) = ' ';
    }
}

Console.WriteLine(str);
Console.WriteLine("Hello world");

The second WriteLine is there to show you why it's a horrible idea.

That code may not always work, and in fact isn't guaranteed to remain working on any current windows machine either. It all depends on where the data for the string object is allocated and the permissions on those pages of memory. Attempting changes like that will eventually result in an access violation, and a forceful termination of your process.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#16 DvDmanDT   Members   -  Reputation: 542

Like
0Likes
Like

Posted 12 July 2011 - 02:11 PM

That code may not always work, and in fact isn't guaranteed to remain working on any current windows machine either. It all depends on where the data for the string object is allocated and the permissions on those pages of memory. Attempting changes like that will eventually result in an access violation, and a forceful termination of your process.


Are you sure?

MSDN says (link)

"You can initialize a pointer with the address of an array or a string:"
and
"fixed (char* p = str) ... // equivalent to p = &str[0]"

So I think it's pretty safe to get the pointer, but I would advice against modifying the data it points to. I seem to recall seeing Microsoft do things like that to compute the string hash while stepping through the standard library.

#17 landlocked   Members   -  Reputation: 103

Like
0Likes
Like

Posted 12 July 2011 - 02:17 PM

The CLR can modify strings if it likes. The prime example is the StringBuilder class implementation from .NET 2.0 to, I believe, 3.5. Internally, that implementation used a string object that got modified. (This got changed - .NET 4.0's StringBuilder uses a char array internally.) If you don't believe me, grab a copy of Reflector and point it at the .NET 2.0 StringBuilder implementation.

This makes me dubious but I'll check it out. It is my understanding StringBuilder took individual strings and just stored them in an array and then ToString simply did one big concatenation instead of doing it incrementally as you added elements (which is why that class exists in the first place). From day one though everything I've read about .NET has touted the immutability of strings so I can't just take your word at this.
Always strive to be better than yourself.

#18 landlocked   Members   -  Reputation: 103

Like
-7Likes
Like

Posted 12 July 2011 - 02:24 PM

Frankly, landlocked, I'm not a fan of your attitude. You appear to be rather confrontational. If you have an argument to be made about a particular topic then you should elucidate your thoughts and reasons, generally backed up with references. Furthermore, this is the .Net forum, not the For Beginners forum. Therefore going in depth into the functionality and behavior of various components of the .Net such as the CLR or CLI is hardly "too deep".

I don't really care what you think of my attitude. About getting "too deep" you should be pushing simple succinct solutions that meet the need rather than trying to be "spiffy" or clever. I write my posts here knowing that someone, anyone, might come along and take what I say and run with it. So, when someone proposes solutions I know to be overly engineered for the problem that was described I will directly counter it and say so.
Always strive to be better than yourself.

#19 Washu   Senior Moderators   -  Reputation: 3974

Like
0Likes
Like

Posted 12 July 2011 - 02:29 PM


That code may not always work, and in fact isn't guaranteed to remain working on any current windows machine either. It all depends on where the data for the string object is allocated and the permissions on those pages of memory. Attempting changes like that will eventually result in an access violation, and a forceful termination of your process.


Are you sure?

MSDN says (link)

"You can initialize a pointer with the address of an array or a string:"
and
"fixed (char* p = str) ... // equivalent to p = &str[0]"

So I think it's pretty safe to get the pointer, but I would advice against modifying the data it points to. I seem to recall seeing Microsoft do things like that to compute the string hash while stepping through the standard library.

Yes, getting a pointer is OK. The access violation can occur if the string is stored in read-only pages and you attempt to modify it. In many cases string constants (like the one you used) get baked into the executable in regions which get loaded into memory with different page permissions than standard dynamically allocated memory (such as what the CLR returns to you), because of this you do have to be aware that making changes to those can result in problems. On average they won't, but it is a possibility that should be kept in mind (and hence avoided).

There usually isn't a reason to bother modifying a string like that anyways, typically the only cases you would need to do that are cases where you're extremely performance constrained. In those cases dropping down to an unmanaged module and letting it do the bulk of the work is probably a better idea (because you can use machine specific instruction sets to boost performance).

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#20 Washu   Senior Moderators   -  Reputation: 3974

Like
5Likes
Like

Posted 12 July 2011 - 02:35 PM

I don't really care what you think of my attitude. About getting "too deep" you should be pushing simple succinct solutions that meet the need rather than trying to be "spiffy" or clever. I write my posts here knowing that someone, anyone, might come along and take what I say and run with it. So, when someone proposes solutions I know to be overly engineered for the problem that was described I will directly counter it and say so.


You should care, because your continued participation on this website depends heavily on your attitude. Keep up the attitude and you might find yourself no longer welcome to continue posting on this site. A well reasoned reply with backing evidence is far more likely to be appreciated than a post that ends with:

STFU.


In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS