while this Code works:
char * k = "asd";
char * j = malloc(sizeof(char) * 3);
memmove(j,k,3);
printf("%s",j);
while code gives error:
char * k = "asd";
char * j = malloc(sizeof(char) * 3);
memmove(k,k+1,3);
printf("%s",k); // output should be "sd"
I am thinking wrong? Why it gives an erorr? I'm planning to use it for deleting the multiple whitespaces ("aaa.......bbb"(dots are spaces) -> "aaa bbb")
Thank you.
A declaration like
char *k = "asd";
causes the string literal to be stored in the read-only data segment. (C compilers tend to not warn for this case even though declaring the pointer as const char *k = "asd" would be safer, for historical reasons.)
If you want the string contents to be modifiable, you will need to use an array instead, like
char k[] = "asd";
When you do char *k = "asd", the string "asd" is placed in the read only parts of memory and the pointer k is made to point there. You cannot write to this location using memmove().
You should instead use char k[] = "asd".
The statement
memmove(k,k+1,3);
tries to shift the elements of string literal asd by 1. String literals are non modifiable. Any attempt to modify it will invoke undefined behavior.
Related
I am trying to remove the whitespace at the start of a string, I have the index of the first non whitespace character, so I tried to do this:
int firstNonWhitespace = ...;
char *line = ...;
char *realStart = line + firstNonWhiteSpace;
strcpy(line, realStart);
but got Abort Trap 6 when at runtime.
However it works if I copy the realStart string to a temporary string, and then copy the temporary string to line:
int firstNonWhitespace = ...;
char *line = ...;
char *realStart = line + firstNonWhiteSpace;
char *tstring = malloc(strlen(realStart) + 1);
strcpy(tstring, realStart);
strncpy(line, tstring, strlen(line));
free(tstring);
There are two problems with your code.
The source and destination in the call to strcpy() do overlap, which results in Undefined Behaviour.
It might well be the case that realStart points to some non-writeable area of memory.
The faster way is
line += firstNonWhiteSpace;
but that might have consequences for your memory management, in case that part of memory was dynamically allocated. Only do this if you know what you are doing.
int main()
{
char a[] = " hey";
int i = 0;
char *p = a;
while(a[i++] == ' ');
strcpy(p, p + i - 1);
printf("%s\n", a);
}
Your problem is likely that you are not allowed to modify string literals, i. e. the code
int main() {
int firstNonWhitespace = 3;
char *line = " foo";
char *realStart = line + firstNonWhiteSpace;
strcpy(line, realStart);
}
may or may not work depending on whether your platform protects against modifying the string literal " foo". Copying the string first is required by the language standard.
Also, since strcpy() is not guaranteed to work correctly on overlapping strings (you might get lucky, though), use memmove() to do the moving.
Here is my code:
printf("%s\n", "test1");
char c = '2';
char * lines[2];
char * tmp1 = lines[0];
*tmp1 = c;
printf("%s\n", "test2");
I don't see the second printf in console.
Question: Can anybody explain me what's wrong with my code?
NOTE: I'm trying to learn C :)
This line:
char * lines[2];
declares an array of two char pointers. However, you don't actually initialize the pointers to anything. So later when you do *tmp1 = (char)c; then you assign the character c to somewhere in memory, possibly even address zero (i.e. NULL) which is a bad thing.
The solution is to either create the array as an array of arrays, like
char lines[2][30];
This declares lines to have two arrays of 30 characters each, and since strings needs a special terminator character you can have string of up to 29 characters in them.
The second solution is to dynamically allocate memory for the strings:
char *lines[2];
lines[0] = malloc(30);
lines[1] = malloc(30);
Essentially this does the same as the above array-of-arrays declaration, but allocates the memory on the heap.
Of course, maybe you just wanted a single string of a single character (plus the terminator), then you were almost right, just remove the asterisk:
char line[2]; /* Array of two characters, or a string of length one */
The array lines in uninitialized. Thus lines[0] is an uninitalized pointer. Dereferencing it in *tmp1 is sheer undefined behaviour.
Here's an alternative, that may or may not correspond to what you want:
char lines[2];
char * tmp1 = lines; // or "&lines[0]"
*tmp = c;
Or, more easily:
char lines[2] = { c, 0 };
lines is uninitialized, and tmp1 initialization is wrong.
It should be:
char lines[2];
char * tmp1 = lines;
Alternatively, you can say:
char * tmp1 = &lines[0];
Or else for an array of strings:
char lines[2][30];
char * tmp1 = lines[0];
The line
char * lines[2];
creates an array of two char pointers. But that doesn't allocate memory, it's just a "handle" or "name" for the pointer in memory. The pointer doesn't point to something useful.
You will either have to allocate memory using malloc():
char * lines = malloc(2);
or tell the compiler to allocate memory for you:
char lines[2];
Note: Don't forget to terminate the string with a 0 byte before you use it.
char *lines[2]; : A two element array of char pointers.
char *tmp; : A pointer to a character.
char *tmp = lines[0] : The value inside the array element 0 of the lines array is transferred into tmp. Because it is an automatic array, therefore it will have garbage as the value for lines[0].
*temp : Dereference the garbage value. Undefined Behaviour.
char * tmp1 = lines[0];
here you declare a char pointer and initialize its pointer value to line[0],the fist element stored in line array which is also uninitialized.
now the tmp is pointing to somewhere unknown and not actually accessible. When you
*tmp1 = (char)c;
you are operating on a invalid memory address which causes a Segmentation fault.
I am trying to understand why the following code is illegal:
int main ()
{
char *c = "hello";
c[3] = 'g'; // segmentation fault here
return 0;
}
What is the compiler doing when it encounters char *c = "hello";?
The way I understand it, its an automatic array of char, and c is a pointer to the first char. If so, c[3] is like *(c + 3) and I should be able to make the assignment.
Just trying to understand the way the compiler works.
String constants are immutable. You cannot change them, even if you assign them to a char * (so assign them to a const char * so you don't forget).
To go into some more detail, your code is roughly equivalent to:
int main() {
static const char ___internal_string[] = "hello";
char *c = (char *)___internal_string;
c[3] = 'g';
return 0;
}
This ___internal_string is often allocated to a read-only data segment - any attempt to change the data there results in a crash (strictly speaking, other results can happen as well - this is an example of 'undefined behavior'). Due to historical reasons, however, the compiler lets you assign to a char *, giving you the false impression that you can modify it.
Note that if you did this, it would work:
char c[] = "hello";
c[3] = 'g'; // ok
This is because we're initializing a non-const character array. Although the syntax looks similar, it is treated differently by the compiler.
there's a difference between these:
char c[] = "hello";
and
char *c = "hello";
In the first case the compiler allocates space on the stack for 6 bytes (i.e. 5 bytes for "hello" and one for the null-terminator.
In the second case the compiler generates a static const string called "hello" in a global area (aka a string literal, and allocates a pointer on the stack that is initialized to point to that const string.
You cannot modify a const string, and that's why you're getting a segfault.
You can't change the contents of a string literal. You need to make a copy.
#include <string.h>
int main ()
{
char *c = strdup("hello"); // Make a copy of "hello"
c[3] = 'g';
free(c);
return 0;
}
I want to initialize arbitrary large strings. It is null terminated string of characters, but I cannot print its content.
Can anybody tell me why?
char* b;
char c;
b = &c;
*b = 'm';
*(b+1) = 'o';
*(b+2) = 'j';
*(b+3) = 'a';
*(b+4) = '\0';
printf("%s\n", *b);
Your solution invokes undefined behaviour, because *(b+1) etc. are outside the bounds of the stack variable c. So when you write to them, you're writing all over memory that you don't own, which can cause all sorts of corruption. Also, you need to printf("%s\n", b) (printf expects a pointer for %s).
The solution depends on what you want to do. You can initialize a pointer to a string literal:
const char *str1 = "moja";
You can initialize a character array:
char str2[] = "moja";
This can also be written as:
char str2[] = { 'm', 'o', 'j', 'a', '\0' };
Or you can manually assign the values of your string:
char *str3 = malloc(5);
str3[0] = 'm';
str3[1] = 'o';
str3[2] = 'j';
str3[3] = 'a';
str3[4] = '\0';
...
free(str3);
This might result in a segmentation fault! *(b+1), *(b+2) etc refer to unallocated areas. First allocate memory and then write into it!
b doesn't have enough space to hold all those characters. Allocate enough space using malloc or declare b as a char array.
Your code is not safe at all! You allocate only 1 char on the stack with char c; but write 5 chars into it! this will give you a stack-overflow which can be very dangerous.
Another thing: you mustn't dereference the string when printing it: printf("%s\n", b);
Why not simply write const char *b = "mojo";?
You need to assign memory space for it, either with malloc or using a static array. Here, in your code, you're using the address of just one character to store at the addresses of that characters, and others following it. This is not defined.
Note, step by step, what you're doing. First, you assign the pointer to point to a single char space in memory. Then, by using *b = 'm' you set that memory to the character 'm'. But then, you access to the next memory position (that is undefined, because no memory is reserved for that position) to store another value. This won't work.
How to do it?
You have two options. For example:
char *b;
char c[5];
b = &c[0];
*b = 'm';
... //rest of your code
This will work because you have space for 5 chars in c. The other option is to directly assign memory for b using malloc:
char * b = (char*) malloc(5);
*b = 'm';
... // rest of your code
Finally, maybe not what you want, but you can either initialize a char array or pointer using a string literal:
char c[] = "hello";
const char* b = "abcdef";
The printf does not print because it expect a char*, so you should pass b, not *b.
To initialize a pointer to a string constant you can do something like:
char *s1 = "A string"
or
char s2[] = "Another string"
or allocate a buffer with char *b = malloc(5) and then write to this buffer (as you did, or with the string functions)
what you did was taking the address of a single char memory location and then write past to it, possibly overwriting other variables or instructions and thus possibly leading to data corruption or crash.
If you write the following instead of your printf, it will print the first character.
printf("%c\n", *b);
In order for you to have arbitrarily large strings, you will need to use a library such as bstring or write one of your own.
This is because, in C one needs to get memory, use it and free it accordingly. b in your case only points to a character unless you allocate memory to it using malloc. And for malloc you have to specify a fixed size.
For arbitrarily large string, you need to encapsulate the actual pointer to character in a data structure of your own, and then manage its size according to the length of the string that is to be set as its value.
printf("%s\n", *b);
why *?
printf("%s\n", b);
is what you want
void reverse(char *str){
int i,j;
char temp;
for(i=0,j=strlen(str)-1; i<j; i++, j--){
temp = *(str + i);
*(str + i) = *(str + j);
*(str + j) = temp;
printf("%c",*(str + j));
}
}
int main (int argc, char const *argv[])
{
char *str = "Shiv";
reverse(str);
printf("%s",str);
return 0;
}
When I use char *str = "Shiv" the lines in the swapping part of my reverse function i.e str[i]=str[j] dont seem to work, however if I declare str as char str[] = "Shiv", the swapping part works? What is the reason for this. I was a bit puzzled by the behavior, I kept getting the message "Bus error" when I tried to run the program.
When you use char *str = "Shiv";, you don't own the memory pointed to, and you're not allowed to write to it. The actual bytes for the string could be a constant inside the program's code.
When you use char str[] = "Shiv";, the 4(+1) char bytes and the array itself are on your stack, and you're allowed to write to them as much as you please.
The char *str = "Shiv" gets a pointer to a string constant, which may be loaded into a protected area of memory (e.g. part of the executable code) that is read only.
char *str = "Shiv";
This should be :
const char *str = "Shiv";
And now you'll have an error ;)
Try
int main (int argc, char const *argv[])
{
char *str = malloc(5*sizeof(char)); //4 chars + '\0'
strcpy(str,"Shiv");
reverse(str);
printf("%s",str);
free(str); //Not needed for such a small example, but to illustrate
return 0;
}
instead. That will get you read/write memory when using pointers. Using [] notation allocates space in the stack directly, but using const pointers doesn't.
String literals are non-modifiable objects in both C and C++. An attempt to modify a string literal always results in undefined behavior. This is exactly what you observe when you get your "Bus error" with
char *str = "Shiv";
variant. In this case your 'reverse' function will make an attempt to modify a string literal. Thus, the behavior is undefined.
The
char str[] = "Shiv";
variant will create a copy of the string literal in a modifiable array 'str', and then 'reverse' will operate on that copy. This will work fine.
P.S. Don't create non-const-qualified pointers to string literals. You first variant should have been
const char *str = "Shiv";
(note the extra 'const').
String literals (your "Shiv") are not modifiable.
You assign to a pointer the address of such a string literal, then you try to change the contents of the string literal by dereferencing the pointer value. That's a big NO-NO.
Declare str as an array instead:
char str[] = "Shiv";
This creates str as an array of 5 characters and copies the characters 'S', 'h', 'i', 'v' and '\0' to str[0], str[1], ..., str[4]. The values in each element of str are modifiable.
When I want to use a pointer to a string literal, I usually declare it const. That way, the compiler can help me by issuing a message when my code wants to change the contents of a string literal
const char *str = "Shiv";
Imagine you could do the same with integers.
/* Just having fun, this is not C! */
int *ptr = &5; /* address of 5 */
*ptr = 42; /* change 5 to 42 */
printf("5 + 1 is %d\n", *(&5) + 1); /* 6? or 43? :) */
Quote from the Standard:
6.4.5 String literals
...
6 ... If the program attempts to modify such an array [a string literal], the behavior is undefined.
char *str is a pointer / reference to a block of characters (the string). But its sitting somewhere in a block of memory so you cannot just assign it like that.
Interesting that I've never noticed this. I was able to replicate this condition in VS2008 C++.
Typically, it is a bad idea to do in-place modification of constants.
In any case, this post explains this situation pretty clearly.
The first (char[]) is local data you can edit
(since the array is local data).
The second (char *) is a local pointer to
global, static (constant) data. You
are not allowed to modify constant
data.
If you have GNU C, you can compile
with -fwritable-strings to keep the
global string from being made
constant, but this is not recommended.