Can I initialize string after declaration?
char *s;
s = "test";
instead of
char *s = "test";
You can, but keep in mind that with that statements you are storing in s a pointer to a read-only string allocated elsewhere. Any attempt to modify it will result in undefined behavior (i.e., on some compilers it may work, but often will just crash). That's why usually you use a const char * for that thing.
Yes, you can.
#include <stdio.h>
int
main(void)
{
// `s' is a pointer to `const char' because `s' may point to a string which
// is in read-only memory.
char const *s;
s = "hello";
puts(s);
return 0;
}
NB: It doesn't work with arrays.
#include <stdio.h>
int
main(void)
{
char s[32];
s = "hello"; // Syntax error.
puts(s);
return 0;
}
It is correct for pointers (as mentioned above) because the string inside quotes is allocated from the compiler at compile time, so you can point to this memory address. The problems comes when you try change its contents or when you have a fixed size array that want to point there
Related
I"m a begginer in C, usually I used C++. I try to work whith a struct with a char array in it, but when I used an other char *str it raises a segfault.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_obj t_obj;
struct s_obj {
char *str;
};
int main() {
char *str; // if disable no segmentation fault
t_obj obj;
printf("%lu\n",strlen(obj.str));
return(0);
}
I tried to understand what you mean by "the argument of strlen must be a string" #anastaciu... so I tried to make a code to do that, but the result is the same: segfault when an other char *str is used.
I can't find a way to init my char *str in the struct.
typedef struct s_obj t_obj;
struct s_obj {
char *str;
};
int main() {
char *str; // if disable no segmentation fault fault
t_obj obj;
obj.str = strcpy(obj.str, "truc");
// printf("%lu\n",strlen(obj.str));
printf("%s\n",obj.str);
return(0);
}
The line
printf("%lu\n", strlen(obj.str));
Invokes undefined behavior, the argument of strlen must be a string, aka a null terminated char array, obj.str is not a string it is just an uninitialized pointer, you'll need to allocate memory for it or othewise make it point to a valid memory location.
For example:
t_obj obj;
obj.str = calloc(100, sizeof *obj.str); //99 character string, 0 initialized
//malloc does not "clear" the allocated memory
//if you use it you can't use strlen before strcpy
printf("%zu\n",strlen(obj.str)); //will print 0, the string is empty
obj.str = strcpy(obj.str, "truc");
printf("%zu\n",strlen(obj.str)); //will print 4, the length of the string
Live demo
Tha fact that the program does not behave as badly when you remove char *str; is a matter that's well within the scope of undefined behavior:
C is not C++ ;) Seems you've missed an important difference regarding the two.
C++ Example:
#include <string>
struct t_obj {
std::string str;
};
void foo(){
t_obj obj; // <-- In C++ this is enough to get a properly initialized instance.
}
In C++, this code will give you a properly initialized object with an (also initialized) string.
But in C (as in your sample):
typedef struct t_obj t_obj;
struct t_obj {
char *str;
};
void foo(){
t_obj obj; // <-- Nothing gets initialized here.
}
There is no initialization as in the C++ example above. obj will simply be a chunk of (not initialized) memory. You have to initialize it yourself.
There's also a Problem with your 2nd sample:
strcpy does not work that way. We need to pass an allocated chunk of memory to strcpy and it will copy data to that place we gave to it.
But as we pass a "not initialzed pointer", strcpy will try to write our data somewhere in memory.
I think question "whats the difference between C strings and C++ strings?" might be helpful. It explains some details about the difference of C and C++ strings.
In either case, you are using obj.str uninitialised.
The address it holds in indeterminate, and the content of the memory location it points to also indeterminate. So, it's not null-terminated, and using it with strlen() (i.e., with the functions which expects a string argument), will cause out of bound access, which is essentially invalid memory access, which in turn invokes undefined behaviour.
For reference, C11, chapter 7.24, String handling <string.h>
[...]Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values,[...]
At least, initialize the pointers to a null-value.
now the code work fine like that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_obj t_obj;
struct s_obj {
char *str;
};
int main() {
char *str;
t_obj obj;
if (!(obj.str = (char*)malloc(sizeof(char))))
return (0);
obj.str = strcpy(obj.str, "truc");
printf("%s\n",obj.str);
free(obj.str);
return(0);
}
Why it stops working? Can't we pass the name of the pointer as an argument for strcpy? if I change it to strcpy(&a,&b); it works.
#include <stdio.h>
int main() {
char *a;
a = "aabtyn";
char *b;
b = "mihli";
strcpy(a,b);
printf("%s-%s\n",a,b);
return 0;
}
Can't we pass the name of the pointer as an argument for strcpy?
Yes, we can. However, it is also important that the destination pointer points to a writeable memory; in your case, neither a nor b point to memory that can be written.
if I change it to strcpy(&a,&b); it works.
If it appears to work on your system, it does so by mistake. What you see is undefined behavior. In order for strcpy to work you need to do one of the following:
Allocate a in automatic memory by defining it as char a[] = "aabtyn";, or
Allocate a in dynamic memory by calling char *a = malloc(7); You need seventh byte for null terminator.
According to the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
You declared two pointers to string literals
char *a;
a = "aabtyn";
char *b;
b = "mihli";
Then in this statement
strcpy(a,b);
you are trying to modify the first string literal. So the behaviour of the program is undefined.
As for this statement
strcpy(&a,&b);
then there is an attempt to copy the value of one pointer to another pointer. This call aslo has undefined behaviour. But if the value of the second pointer is zero-terminated then this call can be equivalent to
a = b;
So the first pointer just reassigned. Though in any case there is undefined behaviour.
A valid program can look the following way
#include <stdio.h>
#include <string.h>
int main( void )
{
char s[] = "aabtyn";
char *a = s;
char *b;
b = "mihli";
strcpy(a,b);
printf("%s-%s\n",a,b);
return 0;
}
If you have:
char source[80],dest[80];
Initialize source, then:
strcpy(dest,source);
But if you have:
char *pd,*ps;
Initialize source,and malloc storage for *pd, then:
strcpy(&pd,&ps);
And remember to have free(pd); somewhere before exit(0);
The code is self-explanatory, but it gives me segmentation fault, why? :\
#include <stdio.h>
int main(void)
{
char *c = "Hella";
*(c+4) = 'o';
printf("%s\n",c);
}
How to avoid it?
Don't modify a string literal!
char *c = "Hella";
Declares a pointer c to a string literal "Hella" stored in implementation defined read only memory.
You are not allowed to modify this literal. An attempt to do so results in Undefined Behavior.
You are lucky that your program crashes, an Undefined Behavior does not always result in a crash but may cause your program to behave weirdly in any possible way.
What you need here is an array:
char c[] = "Hella";
Good Read:
What is the difference between char a[] = ?string?; and char *p = ?string?;?
Put your string into an array allocated onto the stack:
char c[] = "Hella";
Because as said, string literals are usually read-only.
the way you create c it points to a string literal. You can not modify it's contents. If you want to be able to do that use:
char c[6] = "Hella";
c[4] = o;
Or use a dynamically allocated char array.
You are trying to overwrite a literal. Really your code should read:
const char *c = "Hella";
Which kinda explains what is going on.
To overwrite your own memory:
char c[] = "Hella";
is safer.
You can not modify strings that are defined in code. Use strdup if you want to modify them.
#include <stdio.h>
int main(void)
{
char *c = strdup("Hella");
*(c+4) = 'o';
printf("%s\n",c);
free(c);
}
I have this program in C
#include<stdio.h>
int main()
{
printf("Hello New!\n");
char c = 'd';
char* s = "hello world";
char **t = &s;
*t[0] = c;
return 0;
}
The program compiles but doesn't run.
I have this output :
Hello New!
Bus error
I don't understand why
String constants are stored in readonly memory and you cannot modify them.
If you must, then use:
#include<stdio.h>
int main()
{
printf("Hello New!\n");
char c = 'd';
char s[] = "hello world";
char **t = &s[0];
*t[0] = c;
return 0;
}
This allocates a local variable (not a constant) that is conveniently initialized and may be modified to your heart's content.
You may not modify the string that 's' points to, in any way. It is in a part of memory that you are not allowed to change.
String constants are unmodifiable, despite having the type char* rather than const char* for historical reasons. Try using the string constant to initialize an array, rather than a pointer:
#include <stdio.h>
int
main(void)
{
char s[] = "hello new!";
puts(s);
s[0] = 'c';
puts(s);
return 0;
}
A bus error usually means that you're accessing a pointer with an invalid value - e.g. an address that is out of the address space.
I would guess that in this case, it is because you are trying to write to memory that is read-only. The string "hello world" is in a memory segment that you are not allowed to write to. Depending on the operating system, these memory segments are either protected or you can write arbitrary garbage to it. Seems like yours doesn't allow it. As you can see in the other answers, you can work around this by copying/initializing the string constant into an array.
This is a quick program I just wrote up to see if I even remembered how to start a c++ program from scratch. It's just reversing a string (in place), and looks generally correct to me. Why doesn't this work?
#include <iostream>
using namespace std;
void strReverse(char *original)
{
char temp;
int i;
int j;
for (i = 0, j = strlen(original) - 1; i < j; i++, j--)
{
temp = original[i];
original[i] = original[j];
original[j] = temp;
}
}
void main()
{
char *someString = "Hi there, I'm bad at this.";
strReverse(someString);
}
If you change this, which makes someString a pointer to a read-only string literal:
char *someString = "Hi there, I'm bad at this.";
to this, which makes someString a modifiable array of char, initialized from a string literal:
char someString[] = "Hi there, I'm bad at this.";
You should have better results.
While the type of someString in the original code (char*) allows modification to the chars that it points to, because it was actually pointing at a string literal (which are not permitted to be modified) attempting to do any modification through the pointer resulted in what is technically known as undefined behaviour, which in your case was a memory access violation.
If this isn't homework, the C++ tag demands you do this by using the C++ standard library:
std::string s("This is easier.");
std::reverse(s.begin(), s.end());
Oh, and it's int main(), always int main(), dammit!
You're trying to modify a string literal - a string allocated in static storage. That's undefiend behaviour (usually crashes the program).
You should allocate memory and copy the string literal there prior to reversing, for example:
char *someString = "Hi there, I'm bad at this.";
char* stringCopy = new char[strlen( someString ) + 1];
strcpy( stringCopy, someString );
strReverse( stringCopy );
delete[] stringCopy;//deallocate the copy when no longer needed
The line
char *someString = "Hi there, I'm bad at this.";
makes someString point to a string literal, which cannot be modified. Instead of using a raw pointer, use a character array:
char someString[] = "Hi there, I'm bad at this.";
You can't change string literals (staticly allocated). To do what you want, you need to use something like:
int main()
{
char *str = new char[a_value];
sprintf(str, "%s", <your string here>);
strReverse(str);
delete [] str;
return 0;
}
[edit] strdup also works, also strncpy... i'm sure there's a variety of other methods :)
See sharptooth for explanation.
Try this instead:
#include <cstring>
void main()
{
char someString[27];
std::strcpy( someString, "Hi there, I'm bad at this." );
strReverse( someString );
}
Better yet, forget about char * and use <string> instead. This is C++, not C, after all.
When using more strict compiler settings, this code shouldn't even compile:
char* str = "Constant string";
because it should be constant:
const char* str = "Now correct";
const char str[] = "Also correct";
This allows you to catch these errors faster. Or you can just use a character array:
char str[] = "You can write to me, but don't try to write something longer!";
To be perfectly safe, just use std::string. You're using C++ after all, and raw string manipulation is extremely error-prone.