Strings in C : Question!

Community Forums/General Help/Strings in C : Question!

(tu) ENAY(Posted 2011) [#1]
This is a particularly random question but wow, handling strings in C is really complicated. I've figured out how to handle strings now but I can't seem to figure out how to delete the contents of a string without getting a compiler warning.

Anyone know how to do this cleanly?
For example, I have a 3 character string and so far I am deleting it like this:-

grabbed_string = { '\0','\0','\0' } ;


I always get the error
"extended initializer lists only available with -std=c++0x or -std=gnu++0x"


I don't understand the warning but everything works ok and the string is being deleted as it is intended to be. But still, I'd like to know what is wrong.

Any tips? :)


AltanilConard(Posted 2011) [#2]
Cant you use grabbed_string = ""; ?


(tu) ENAY(Posted 2011) [#3]
You would think that would work wouldn't you? But you can't do that in C, it will throw an error. Something along the lines of "You can't assign a const to a non const variable" type of error.

C is fiddly, for example you can't even do stringa = stringb;


AltanilConard(Posted 2011) [#4]
Well, you'd use a char* ofc, something like:
char* str = "hello";
printf("%s \n", str);
str = "bye";
printf("%s \n", str);

should work. What are you trying to do?


(tu) ENAY(Posted 2011) [#5]
Ok, I was using a char and not a char* despite the fact I was passing a char* into a function.
What I am simply trying to do loop through each character of a string and pick out a single character Mid$ style. It works but kept coming up with that warning. But clearly I was just declaring the string incorrectly.


big10p(Posted 2011) [#6]
Are we talking about plain C here, or C++? C doesn't actually have strings; it has 'arrays of characters'.

Conard: My C is very rusty but I think that code will just create a memory leak.


AltanilConard(Posted 2011) [#7]
Pointers get me so confused.
big10p is right, in my example "hello" is still in memory; you must somehow free it and allocate new.
I'm going to open that old C book and read the pointer chapter once again.


big10p(Posted 2011) [#8]
Actually, I'm not sure there is a way to free string memory. G'ah, can't remember.


Canardian(Posted 2011) [#9]
Just use C++ string. They are faster than any self-written C string functions with all the dynamic memory allocation and releasing.


Yasha(Posted 2011) [#10]
I don't really understand the question, but the basic thing you need to remember is that there are no strings in C; you have to allocate and deallocate blocks of memory manually. I have no idea what you're trying to do in the first post, but you're definitely not deleting a string, just putting another one into the variable.

Meanwhile, the string syntax is just a nice shortcut that creates a statically allocated block of characters somewhere in the executable's memory (so you shouldn't free or modify those or you will invoke our friend Undefined Behaviour!).

Judging by your first listed error message, if you're using C++ rather than C (they aren't the same language!), Lumooja's right: you're better off using C++ strings instead, which provide a lot of the Basic-style syntax you're used to and largely look after themselves.

Last edited 2011


Czar Flavius(Posted 2011) [#11]
Conard's code won't leak memory. String literals which are embedded into the code are stored once in a global memory region (as Yasha described). When you make the pointer equal "hello", it sets the pointer to that (constant) memory block. Then you make the pointer equal "bye", it sets the pointer to the bye memory block. When you go through the function again, it just sets back to "hello" again. There is only ever one set of "hello" and "bye" in memory. They are basically stored in global arrays, and you only reference them. The code snippet allocates NO dynamic memory.

The original code doesn't work because you can only use { } syntax to initialize something for the first time, not give it another value later. It's also important to understand the difference between char and char *.

If you can, std::string in C++ is a lot easier to use (although still not as nice as Blitz strings). C-style strings are faster if you are doing something heavy duty, but I wouldn't worry about it in general.

Last edited 2011


(tu) ENAY(Posted 2011) [#12]
I know it's easy to just include the C++ string header file but doing so takes up valuable memory which is why I was doing it in C. I just wanted to know how to nullify a string in C so that the string is empty. \0 certainly does the trick except for the warning.


Yasha(Posted 2011) [#13]
I just wanted to know how to nullify a string in C so that the string is empty.


The point is that it depends very much on what you mean by "nullify", because (as is pointed out above), C doesn't have a string type and therefore you could be talking about a couple of different operations that a Basic style string system would handle behind the scenes.

Setting all characters to 0 will cause standard string functions to think that you're passing "", but the object in memory will be the same size - because it's still the same object (incidentally, you should only need to set the first character to 0 as such functions iterate along the string to find the end point - setting anything past that is unnecessary, so you could do grabbed_string[0] = 0).

Anyway, this means that you're still using memory for the characters you aren't using, and can't put more than that number of characters into that buffer. Also, unless you store the length of the buffer somewhere, you won't have any safe way to re-lengthen the string (within the bounds of the buffer).

The simple solution with C strings is to simply allocate a new string each time you want something new, and free the old one. Behind the scenes reference counting as used by BlitzMax (and most other languages that have a string type) is kinda useful for this. Actually modifying strings in place is really not recommended for most tasks (certainly nothing resembling the way you would use strings in Blitz).

To sum it up: C does not support strings in any meaningful way, and if you want to use C-style strings you need to stop thinking about them as a value type the way one does for Blitz, because they aren't.


(tu) ENAY(Posted 2011) [#14]
That's really advice yasha, I thought though that my securing a bit of memory and just nullifying it each time that it would be the most useful approach. Setting all the characters to zero isn't a null string since it actually contains something. If you know how to deallocate and allocate new stings then that would be really handy information to know.


Yasha(Posted 2011) [#15]
If you know how to deallocate and allocate new stings then that would be really handy information to know.


Uh... malloc, generally (or whatever allocator function you're using):

char * my_str = malloc(sizeof(char) * (desired_length + 1));


...remembering of course that the contents of this block are undefined until you put something in them. You need to then manually set the characters, and manually set the null character.

To be honest, if you're not already familiar and totally comfortable with using malloc and free, and happy using C pointers, you'll have some difficulty with this. Strings grow out of basic C-language principles.

Say you wanted to do this (Blitz), where s1 and s2 are strings:
s1 = s1 + s2

...in C, you'd do something more like:
char * temp = malloc(sizeof(char) * (strlen(s1) + strlen(s2) + 1));
strncpy(temp, s1, strlen(s1));
strncpy(temp + strlen(s1), s2, strlen(s2) + 1);
free(s1);
s1 = temp;

... phew (hopefully I got that right). Now you could wrap this up and make it tidier, but you have to understand that you're still doing something like that.

Note also that C++ strings won't suffer from memory leaks if you get it wrong: your program may get a bit bigger, but it will be a lot more reliable and readable.

I thought though that my securing a bit of memory and just nullifying it each time that it would be the most useful approach.


If your string is some kind of code or identifier, and is always the same length, you could arguably do something like this. It really depends so much on what you want to do.

Last edited 2011


Czar Flavius(Posted 2011) [#16]
As Yasha states, there are many different ways of handling strings in C/C++, each with their pros and cons. For example, malloc'd strings are considerably slower than stack-based strings. Is saving a few bytes worth it?

If you explain exactly what you are trying to do, we could make some better recommendations.

Warnings in C shouldn't be ignored unless you know what they entail. What is the warning?

Note that you CANNOT modify string literals. The following code is very bad.

char * mystr = "Hello there";
mystr[0] = '\0';

This is because it alters the actual static memory where the string literal is stored. The next time you come across that line, "Hello there" has actually been permanently erased!

If you want to modify the string, you will need to create your own storage and copy the string.

My old-style C is a bit rusty, so this may have syntax errors..

Either you can go down the stack or dynamic route. Stack is much faster, but your string must have a fixed upper size and the string doesn't survive beyond that level of scope. Dynamic is slower, but you can pick your size at run-time and return the string (or more correctly, a pointer to the string) from the function.

Stack
void f()
{
	char mystring[32]; /* max 31 char + 1 terminating char, don't forget to accomodate it */
	strcpy(mystring, "Hello world");
	mystring[5] = '\0';
	/* go nuts */

	/* DON'T DO THIS. you couldn't anyway because of the function being void.. */
	return mystring; /* does not exist after function */
}


As a shortcut, you can initialize an array from a string literal and let it determine the size for you automatically.

char mystring[] = "Hello there"; /* takes just enough space */


The advantage of the first method is you could give yourself more room if you want to expand the string.

This uses stack storage, which is fixed, eg 4mb stack. Saving a few bytes here and there won't affect any memory usage and probably won't risk stack overflow unless your strings are hundreds of characters in size simultaneously.

Here is dynamically
void f()
{
	static char * datasource = "Hello world"; /* don't modify this pointer */
	/* allocate enough storage for the source string, 32 extra characters and don't forget the terminator */
	char * mystring = (char *) malloc(sizeof(char) * (strlen(datasource) + 32 + 1));
	/* copy the source string */
	strcpy(mystring, datasource);

	/* this can append to a string, give it a pointer to the current position of the first terminating character. overflow its size at your peril */

	sprintf(mystring + strlen(datasource), "%s", "I am adding");

	printf("%s", mystring"); /* "Hello worldI am adding" */

	/* remember or it will leak */
	free(mystring);

	/* you could also return this string from the function and it will still exist. but you must free it at some point, free it only once and not use any pointers to the memory block after it has been freed */

}