Run-time error in program - c

int main()
{
char *p="abcd";
while(*p!='\0') ++*p++;
printf("%s",p);
return 0;
}
I am not able to understand why the code does not run. The problem is in the statement ++*p++, but what is the problem?

P points to constant string literal *p="abcd"; by doing ++*p++ you are trying to modify string '"abcd"', for example a in string will be increment to 'b' because of ++*p that is undefined behavior (constant string can't change). it may cause a segmentation fault.
`++*p++` means `++*p` then `p++`
^
| this operation try to modify string constant

char *p="abcd";
p is pointing to a readonly segment and you can not increment p as you did here
while(*p!='\0') ++*p++;

//char *p="abcd";//"string" is const char, don't change.
char str[]="abcd";//is copied, including the '\0' to reserve space
char *p = str;
while(*p!='\0') ++*p++;
//printf("%s",p);//address pointing of 'p' has been changed
printf("%s",str);//display "bcde"

char *foo = "abcd";
char bar[] = "abcd";
Consider the differences between foo and bar. foo is a pointer that's initialised to point to memory reserved for a string literal. bar is an array with it's own memory that's initialised to a string literal; it's value is copied from the string literal during initialisation. It is appropriate to modify bar[0], etc, but not foo[0]. Hence, you need an array declaration.
However, you can't increment an array declaration; That's an operation for pointer variables or integer variables. Additionally, your loop changes where p points at, before it's printed, so you need to keep the original location of your string somewhere. Hence, you also need a pointer, or an integer declaration.
With this in mind, it might seem like a good idea to change your code to something like this:
int main()
{
char str[] = "abcd";
/* Using a pointer variable: */
for (char *ptr = str; *ptr != '\0'; ++*ptr++);
/* Using a size_t variable: */
for (size_t x = 0; str[x] != '\0'; str[x++]++);
printf("%s", str);
return 0;
}

Related

Assigning char to char* using pointers

Let's say I have a char *str and I want to assign it characters one by time using using pointers and incrementing ?
I've done :
char *str;
char c = 'a';
*str++ = c;
But it doesn't work.
How can I do that ?
str is just a pointer. It doesn't point anywhere valid (especially not to some memory you could write to). A simple possibility would be to have it point to an array:
char buf[1024] = {0}; // room for 1024 chars (or 1023 + a 0 byte for a string)
char *str = buf;
char c = 'a';
*str++ = c;
char *str is a pointer to a char (or an array of chars), however, you never assigned it. As has been mentioned earlier a char * basically says "go there" but there is no there there, you never gave it a value. You first need to use malloc to create space to put things in. Here's an example
char *str = malloc(sizeof(char)*10) //allocate space for 10 chars
char c = 'a';
str[0] = c;
no error check was made to malloc which you should do in your own program. You can also do it as such
char str[10];
char c = 'a';
str[0] = c;
however with this method you will be restricted to 10 chars and you cannot change that amount, with the previous method you can use realloc to get more or less space in your array.
But it doesn't work.
char* str;
... is not initialized to anything, therefore dereferencing it is to undefined behaviour. If it where initialized, then in expression *str++ = c; str++ is a post-increment operator, which returns a copy of the pointer whilst incrementing the original. The effect is that the copy points to the previous, and therefore what is pointed to by the previous pointer is assigned c.
To which part that doesn't work are you referring?
EDIT:
As mentioned in one of the comments, a copy is not really returned but the value is increment in place after having been evaluated.
As a variable with automatic storage duration the pointer str has indeterminate value. If even it had the static storage duration its value would be NULL. So you may not use such a pointer to store data.
What you mean can look for example the following way
#include <stdio.h>
int main( void )
{
char s[11];
char *p = s;
while (p != s + sizeof( s ) / sizeof( *s ) - 1 ) *p++ = 'a';
*p = '\0';
puts(s);
return 0;
}
The program output is
aaaaaaaaaa
Here in the program the pointer p of the type char * is initialized by the address of the first character of the array s.
Thus this statement used in the loop
*p++ = 'a';
fills sequentially the array with the character 'a'.
The next example is more interesting
#include <stdio.h>
char * copy_string(char *dsn, const char *src)
{
for (char *p = dsn; (*p++ = *src++) != '\0'; )
{
// empty body
}
return dsn;
}
int main( void )
{
char *src = "Hi QBl";
char dsn[7];
puts(copy_string(dsn, src));
return 0;
}
The program output is
Hi QBl
Here is a demonstration of a function that copies one character array containing a string into another character array using pointers.

Error in string initialisation

Here I was trying out the following thing in my code and got the following error---"prog.c:10:8: error: incompatible types when assigning to type ‘char[100]’ from type ‘char *’". Please help and tell me how can I modify my initialisation which is char str[100] to get the right answer
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[100];
str = "a";
str = str + 1;
str = "b";
str = str + 1;
str = "c";
str = str + 1;
printf("%s", str - 2);
return 0;
}
You have declared an array
char str[100];
By specifying the name of the array you will get the base address of the array which is same as the address of first element.
str="a";
In the above statement, you are trying to assign "a"s (note "a" is string here) address to array base.
The compiler will not allow you to do this. Cos, if you do so, you will lose all the 100 elements.
If you want to assign the first element with the value 'a', then do
str[0] = 'a';
Note that I have used single quote. Remember "Single quote for single char".
You have to use string commands like strcpy/strncpy.
Or you can allocate memory to accomodate the string and use only char pointers, no char array.
while arrays and pointers are closely related in C, they are not entirely the same.
char str[100];
gives you a "const pointer"-like handle to a pre-allocated array of 100 chars. this array will live at a fixed position in memory, so you cannot let str point to some other place.
str="a";
will assign the position of a string "a" to the pointer "str". (which is illegal!).
what you can do, is to assign the values within your array.
char str[100] = {0};
str[0]='a';
str[1]='b';
str[2]='c';
printf("%s", str);
treat str as an array and not as a pointer (str points to a memory address allocated for 100 chars and str[i] accesses the relative memory address of str + i)
char str[100];
str[0]='a';
str[1]='b';
str[2]='c';
str[3]='\0';
printf("%s",str);
if want initialisation a str[100],use this:
char str[100] = "abc";
it only work when we define the str[100] and initialisation str[100] at the same time!
Or you code can work in this way:
char str[100];
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
Or :
char str[100];
*str = 'a';
++str;
*str = 'b';
++str;
*str = 'c';
++str;
*str = '\0';
In general when you create an array of characters like this.
char string[100]; //allocate contigious location for 100 characters at compile time
Here string will point to the base address of the contigious location. Assuming memory address starts from 4000 then it would be like
--------------------------------------
|4000|4001|4002|4003|...........|4099|
--------------------------------------
Variable string will point to 4000. To store a value at 4000 you can do *(4000).
Here you can do like
*string='a'; //4000 holds 'a'
*(string+1)='b'; //4001 holds 'b'
*(string+2)='c'; //4002 holds 'c'
Note: Array can be accessed by any of the three forms in c.
string[0] => 0[string] => *(string+0) => points to first element in string array
where
string[0] => *(4000+0(sizeof(char))) => *(4000)
0[string] => *((0*sizeof(char))+4000) => *(4000)
*string => *(4000)
In case of integer array, assuming int takes 4bytes of memory
int count[100]; //allocate contigious location for 100 integers at compile time
Here count will point to the base address of the contigious location. Assuming memory address starts from 4000 then it would be like
--------------------------------------
|4000|4004|4008|4012|...........|4396|
--------------------------------------
variable count will point to 4000. To store a value at 4000 you can do *(4000).
Here you can do like
*count=0; //4000 holds 0
*(count+1)=1; //4004 holds 1
*(count+2)=2; //4008 holds 2
So coming to your code, your objective can be achieved like this.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char str[100];
*str='a';
*(str+1)='b';
*(str+2)='c';
printf("%s",str);
return 0;
}
Output: abc
You persist in using the wrong term, which leads me to believe that is why you couldn't find an answer.
/* 1 */
char str[100] = "a"; //OK
/* 2 */
str = "b"; // error: str is an array
Initialization is what happens when you assign a value to a variable while declaring the variable. This is source code excerpt 1 above.
Assignment is what happens after the variable is declared. You can't assign to a struct or array type. You must address each individual item in the struct/array when assigning values. In code excerpt 2 above, the variable str is assigned the value "b", except that str is an array, so the compiler says there is an error because you can't assign to an array.
Summary:
You can initialize an array, but you cannot assign to it. The difference is in whether the variable was given an explicit value when it was declared. If it was, the variable was initialized. Otherwise, you're trying to assign to an array, which can't be done.
Many, even I when learning c, was confused like you.
Actually you must be clear on this
Difference between `char []` and `char *`
=>char [] is a constant pointer which refers to the same address every time. But its value is not constant
=>char * is a non-constant pointer which can be changed to refer to any string. Its value is also not constant, but if it is assigned the address of a const char * then its value will be const.
Coming to your question
Use methods instring.h
#include<stdio.h>
#include<stdlib.h>
int main()
{
char string[100];
char *str;
*str = 'a';
str = str + 1;
*str = 'b';
str = str + 1;
*str = 'c';
str = str + 1;
printf("%s", str - 2);
return 0;
}

unexpected error on printing string

Why does this code produce an error? Shouldn't it output zbcde?
int main()
{
char *p="abcde";
*p='z';
printf("%s\n",p);
return 0;
}
You're trying to modify a string literal; it's undefined behavior.
Further explanation: "abcde" is not a char * but a const char *. You should do one of the following solutions:
char p[] = "abcde";
or
char *p = strdup("abcde");
(in the latter case, don't forget to free() p!)
char *p="abcde"; - This will keep the string abcde in text segement as read only data and the address will be kept in the local pointer variable p.
*p = 'z' will tries to replace the read only data a to z. Which is an undefined behaviour, which can leads to crash.
So declare the string as local char array variable as below.
char p[] = "abcde"
So allocate dynamic memory to keep the string like below.
char *p = strdup("abcde");
...
free(p);

Difference between char *str="STRING" and char str[] = "STRING"?

While coding a simple function to remove a particular character from a string, I fell on this strange issue:
void str_remove_chars( char *str, char to_remove)
{
if(str && to_remove)
{
char *ptr = str;
char *cur = str;
while(*ptr != '\0')
{
if(*ptr != to_remove)
{
if(ptr != cur)
{
cur[0] = ptr[0];
}
cur++;
}
ptr++;
}
cur[0] = '\0';
}
}
int main()
{
setbuf(stdout, NULL);
{
char test[] = "string test"; // stack allocation?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // works
printf("After: %s\n",test);
}
{
char *test = "string test"; // non-writable?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // crash!!
printf("After: %s\n",test);
}
return 0;
}
What I don't get is why the second test fails?
To me it looks like the first notation char *ptr = "string"; is equivalent to this one: char ptr[] = "string";.
Isn't it the case?
The two declarations are not the same.
char ptr[] = "string"; declares a char array of size 7 and initializes it with the characters s ,t,r,i,n,g and \0. You are allowed to modify the contents of this array.
char *ptr = "string"; declares ptr as a char pointer and initializes it with address of string literal "string" which is read-only. Modifying a string literal is an undefined behavior. What you saw(seg fault) is one manifestation of the undefined behavior.
Strictly speaking a declaration of char *ptr only guarantees you a pointer to the character type. It is not unusual for the string to form part of the code segment of the compiled application which would be set read-only by some operating systems. The problem lies in the fact that you are making an assumption about the nature of the pre-defined string (that it is writeable) when, in fact, you never explicitly created memory for that string yourself. It is possible that some implementations of compiler and operating system will allow you to do what you've attempted to do.
On the other hand the declaration of char test[], by definition, actually allocates readable-and-writeable memory for the entire array of characters on the stack in this case.
As far as I remember
char ptr[] = "string";
creates a copy of "string" on the stack, so this one is mutable.
The form
char *ptr = "string";
is just backwards compatibility for
const char *ptr = "string";
and you are not allowed (in terms of undefined behavior) to modify it's content.
The compiler may place such strings in a read only section of memory.
char *test = "string test"; is wrong, it should have been const char*. This code compiles just because of backward comptability reasons. The memory pointed by const char* is a read-only memory and whenever you try to write to it, it will invoke undefined behavior. On the other hand char test[] = "string test" creates a writable character array on stack. This like any other regualr local variable to which you can write.
Good answer #codaddict.
Also, a sizeof(ptr) will give different results for the different declarations.
The first one, the array declaration, will return the length of the array including the terminating null character.
The second one, char* ptr = "a long text..."; will return the length of a pointer, usually 4 or 8.
char *str = strdup("test");
str[0] = 'r';
is proper code and creates a mutable string. str is assigned a memory in the heap, the value 'test' filled in it.

Why does *(str+i) = *(str +j) not work here?

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.

Resources