Trying to copy a string into a const char * array in C - c

I am trying to convert a string in C (using the string.h library) into a const char array.
int len = sizeof(the_string);
const char *char_array = malloc(len);
strcpy(char_array, the_string);
I have pored through the string.h method file and googled it but things keep coming up in C++. Any advice would be greatly appreciated, thank you!!!

This declaration of a pointer
const char *char_array;
means that you may not change the memory pointed to by the pointer using the pointer.
You could make the pointer itself a constant object like
char * const char_array = malloc( some_size );
In this case you may not reassign the pointer itself but you may change the memory pointed to by the pointer.
Take into account that the expression sizeof(the_string) does not make a great sense if you are going to know the length of a string stored in a character array because in general a character array can be much larger than the stored string in it. Instead you should write
size_t len = strlen( the_string );
Using the expression sizeof(the_string) makes a sense in declarations such this
char the_string[] = "Hello";
that is when the size of a character array is determined by the size of a string literal used as an initializer.

Related

How do i determine the length of a string if it's declared as const char *str?

I have the following function structure
int function(const char *str)
{
return 0;
}
I never could fully understand why people use char *str rather than simply string str. So I am guessing this basically means that the argument is the pointer to the first character of the string. How do I determine the length of the string str given that argument?
What I've tried is to iterate through str, if I hit a NULL or "" or '', then that will be the end of it. However, none of these types are compatible for comparison. Please give me some clue regarding this. Thx!
Jamesdlin's answer is good, but to answer your question about comparisons, you would use '\0', IE:
char* a = "a";
int size = 0;
while (a[size] != '\0')
size++;
NULL is a pointer macro, "" is an empty character array (Though it has an implicit '\0', so you could theoretically do strcmp(a, "");), and '' is just an empty character, I'm not sure that it's even a valid statement.
Also, std::string is a C++ class and does not exist in the C standard library.
In C, strings are typically NUL-terminated. For NUL-terminated strings, you can simply call strlen(str).
I never could fully understand why people use char *str rather than simply string str.
There is no string type in C. You could add a typedef:
typedef char* string;
But adding typedefs for pointer types is generally a bad idea (because now you need a separate typedef for const char*; const string would not be the same thing).
And while doing so might seem like a good idea, in practice it will obscure your code since char*/const char* for strings is the norm.
You are almost correct, char *str is a pointer to the first character of a char array, but C has no predefined string type - it's just a zero-terminated char array. Instead of trying to write a function (although it would be a good student exercise), just call the library function in <string.h> with strlen (str); which takes a pointer to the character array. You don't pass *str or &str but just str if it is a declared array variable. If memory was allocated dynamically, you pass the allocated pointer, so if the pointer was declared as char *memstr you pass it as memstr. As others have said, it's best not to try to define a string, better to understand how the char array works.

How to change a character in a string using pointers?

im having troubles with this code
int main() {
char *My_St = "abcdef";
*(My_St+1)='+';
printf("%s\n",My_St);
return 0;
}
i built this code and has no errors, but when i try to run it, it throws a segmentation fault, could someone tell what's wrong
You can't because you are trying to modify const data.
change it to:
char My_St[] = "abcdef";
Then you will be able to change it.
Think about what you were doing, you were declaring a pointer that pointed to "abcdef". It IS a pointer, not an array of chars. "abcdef" lives in the farm, I mean, in the .text area of your program and that is immutable.
When you do it the way I've shown, you are telling the compiler: i'm declaring this array, that will have as many chars as are needed to accommodate "abcdef" and also, as you are there, copy "abcdef" to it.
You provided a hint to the compiler by declaring My_St with type char *. Assigning a string literal to this pointer essentially makes it a const char * because a string literal cannot be modified, meaning the memory location is read-only. Writing to that read-only memory location is what is producing your segfault. Change it from char *My_St to char My_St[] to get it working.
char *My_St refers to constant memory, most likely. You will need to dynamically allocate your string and then fill it (using strcpy).
char *str = malloc(7);
strcpy(str, "abcdef");
Or
char *str = strdup("abcdef");
And then it is safe to modify str.
The basics are correct, however your character string is (behind the scenes) constant and can't be modified. You'd have to define a array of chars (e.g. char[20]), copy the string into it and then modify the character.
To be 100% correct you'd have to write const char *My_St = "abcdef"; which makes it clearer that you can't do what you're trying to do.

How to properly initialize a string

How would I go about defining the following string for the following function?
As of now I get the warning:
C4047: '=' : 'const char' differs in levels of indirection from 'char [4]'
and the error:
C2166: l-value specifies const object.
Both in the third line of the code below:
uint8_t *buffer= (uint8_t *) malloc(sizeof(uint32_t));
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
newval = protobuf_writeString (buffer, stringaling);
uint32_t protobuf_writeString(uint8_t *out,const char * str)
{
if (str == NULL)
{
out[0] = 0;
return 1;
}
else
{
size_t len = strlen (str);
size_t rv = uint32_pack (len, out);
memcpy (out + rv, str, len);
return rv + len;
}
}
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
This is not valid code. You are trying to assign to a const variable, which is illegal. Then you are trying to assign an array of characters to a character. And finally, even if you had a non-const array of characters of the right size, you still can't assign arrays, because they're not first-class values.
Try using
char *stringaling = malloc(sizeof(uint32_t));
strcpy(stringaling, "fun");
...instead, and see if that doesn't work better. Note, however, that it's pretty much accidental that (at least usually) sizeof(uint32_t) happens to be the right size to hold "fun". You normally don't want to do that.
Alternatively, you may want:
char const *stringaling = "fun";
or:
char stringaling[] = "fun";
The assignment you had won't work though -- C has only the very most minimal support for strings built into the language; most operations (including copying a string) are normally done via library functions such as strcpy.
"fun" is a string literal, which is essentially a const char *.
stringaling is also a const char *, so your third line is trying to assign a const char * to a const char, which is not going to fly.
If it's a constant string, you can just do this:
const char *stringaling = "fun";
If your input string is dynamic, you can do this:
char *stringaling= (char *) malloc(strlen(inputString)+1);
strcpy(stringaling, inputString);
Obviously, if you malloc it, you need to free it, or feel the wrath of a memory leak.
If you really want to initialize the char *, you could write this instead:
const char *stringaling = "fun";
And here's some reference.
without all the stuff you can also use:
newval = protobuf_writeString (buffer, "fun" );
First problem:
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
Several problems on this line.
First of all, you don't want to declare stringaling as const char *; you will not be able to modify whatever stringaling points to (IOW, *stringaling will not be writable). This matters since you want to copy the contents of another string to the location pointed to by stringaling. Drop the const keyword.
Secondly, malloc(sizeof(uint32_t)) just happens to allocate enough bytes (4) for this particular string, but it's not clear that you meant to allocate 4 bytes. When allocating memory for an array (and strings are arrays), explicitly indicate the number of elements you intend to allocate.
Finally, casting the result of malloc is considered bad practice in C. The cast will suppress a useful diagnostic message if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope. As of the 1989 standard, malloc returns void *, which can be assigned to any other object pointer type without needing to cast. This isn't true in C++, so a cast is required there, but if you're writing C++ you should be using new instead of malloc anyway.
So, change that line to read
char *stringaling = malloc(LEN); // or malloc(LEN * sizeof *stringaling), but
// in this case that's redundant since
// sizeof (char) == 1
where LEN is the number of chars you want to allocate.
The general form for a malloc call is
T *p = malloc (N * sizeof *p);
where T is the base type (int, char, float, struct ..., etc.), and N is the number of elements of type T you want to allocate. Since the type of the expression *p is T, sizeof *p == sizeof(T); if you ever change the type of p, you don't have to replicate that change in the malloc call itself.
Second problem:
*stringaling = "fun";
Again, there are several issues at play. First, you cannot assign string values using the = operator. String literals are array expressions, and in most contexts array expressions have their type implicitly converted ("decay") from "N-element array of T" to "pointer to T". Instead of copying the contents of the string literal, you would be simply assigning a pointer to the first character in the string.
Which would "work" (see below), except that you're dereferencing stringaling in the assignment; the type of the expression *stringaling is const char (char after making the change I indicated above), which is not compatible for assignment with type char *. If you drop the dereference operator and write
stringaling = "fun";
you'd fix the compile-time error, but now you have another problem; as mentioned above, you haven't copied the contents of the string literal "fun" to the memory block you allocated with malloc; instead, you've simply copied the address of the string literal to the variable stringaling. By doing so, you lose track of the dynamically-allocated block, causing a memory leak.
In order to copy the string contents from one place to another, you'll have to use a library function like strcpy or strncpy or memcpy, like so:
strcpy(stringaling, "fun");
If stringaling doesn't need to live on the heap (for example, you're only using it within a single function and deallocating it before returning), you could avoid memory management completely by declaring it as a regular array of char and initializing it with "fun":
char stringaling[] = "fun";
This is a special case of initializing an array in a declaration, not an assignment expression, so the = does copy the contents of the string literal to the stringaling array. This only works in an array declaration, however. You can later modify the array with other string values (up to 3 characters plus the 0 terminator), but you'd have to use strcpy again:
strcpy(stringaling, "one");
If you don't need to modify the contents of stringaling, you could just do
const char *stringaling = "fun";
This copies the address of the string literal "fun" to the variable stringaling. And since attempting to modify the contents of a string literal invokes undefined behavior, we do want to declare stringaling as const char * in this case; that will prevent you from accidentally modifying the string literal.

char* vs const char* as a parameter

There are many times that I get compile errors when I use char* instead of const char*. So, I am not sure the actual difference, the syntax and the compile mechanism.
If you're after the difference between the two, just think of them as:
char* is a pointer that points to a location containing a value of type char that can also be changed. The pointer's value can be changed, i.e. the pointer can be modified to point to different locations.
const char* is a pointer, whose value can be also changed, that points to a location containing a value of type char that cannot be changed.
const char * means "pointer to an unmodifiable character." It's usually used for strings of characters that shouldn't be modified.
Say you're writing this function:
int checkForMatch(const char * pstr)
You've promised (through the function signature) that you will not change the thing pointed to by pstr. Now say part of checking for a match would involve ignore the case of letters, and you tried to do it by converting the string to upper case before doing your other checks:
strupr(pstr);
You'll get an error saying you can't do that, because strupr is declared as:
char * strupr(char* str);
...and that means it wants to be able to write to the string. You can't write to the characters in a const char * (that's what the const is for).
In general, you can pass a char * into something that expects a const char * without an explicit cast because that's a safe thing to do (give something modifiable to something that doesn't intend to modify it), but you can't pass a const char * into something expecting a char * (without an explicit cast) because that's not a safe thing to do (passing something that isn't meant to be modified into something that may modify it).
Of course, this is C, and you can do just about anything in C, including explicitly casting a const char * to a char * — but that would be a really, really bad idea because there is (presumably) some reason that the thing being pointed to by the pointer is const.
char *       : non-constant pointer to non-constant character
const char *    : non-constant pointer to constant   character
char *const     : constant   pointer to non-constant character
const char * const : constant   pointer to constant   character
Reference [link]
I always try to define parameters with const char* not char* because converting from std::string to conts char* is easy by .c_str() method. However converting std::string to char* is not that easy.
Probably I'm too picky. In my book, the character(s) pointed to by a const char* can possibly be changed but not via the const char*. A const char * can point to modifiable storage. Example:
char a[] = "abracadabra";
const char * ccp = &a[0]; // ccp points to modifiable storage.
*&a[0] = 'o'; // This writes to a location pointed to by const char* ccp
So, my wording is:
A char * is a pointer that be changed and that also allows writing through it when dereferenced via * or [].
A const char * is a pointer that be changed and that does not allow writing through it when dereferenced via * or [].

Why can I change the value of a const char* variable?

Why does the following code in C work?
const char* str = NULL;
str = "test";
str = "test2";
Since str is a pointer to a constant character, why are we allowed to assign it different string literals? Further, how can we protect str from being modified? It seems like this could be a problem if, for example, we later assigned str to a longer string which ended up writing over another portion of memory.
I should add that in my test, I printed out the memory address of str before and after each of my assignments and it never changed. So, although str is a pointer to a const char, the memory is actually being modified. I wondered if perhaps this is a legacy issue with C?
You are changing the pointer, which is not const (the thing it's pointing to is const).
If you want the pointer itself to be const, the declaration would look like:
char * const str = "something";
or
char const * const str = "something"; // a const pointer to const char
const char * const str = "something"; // same thing
Const pointers to non-const data are usually a less useful construct than pointer-to-const.
Further, how can we protect str from being modified?
char * const str1; // str1 cannot be modified, but the character pointed to can
const char * str2; // str2 can be modified, but the character pointed to cannot
const char * const str3 // neither str3 nor the character pointed to can be modified.
The easiest way to read this is to start from the variable name and read to the left:
str1 is a constant pointer to a character
str2 is a pointer to a character constant
str3 is a constant pointer to a character constant
NOTE: the right-to-left reading does not work in the general case, but for simple declarations it's a simple way to do it. I found a java applet based on code from "The C Programming Language" that can decipher declarations with a full explanation of how to do it.
On a related note, definitely take a look at "const pointer versus pointer to const". It helps with what some people call const correctness. I keep it in my bookmarks so that I can refer to it every now and then.
What you're looking for may be the syntax...
const char* const str = NULL;
str = "test";
str = "test2";
Notice the "const" after the char* which yields a compiler error when trying to compile/build.
Memory for the string literals are allocated on the stack, and all your assignments do are change the str pointer to point to those memory addresses. The constant character it pointed to initially hasn't changed at all.
Besides, declaring a variable as const means that variable is read-only; it does not mean the value is constant!

Resources