what is the pointer error in this code? - c

I am trying to understand pointers and here is a program in K&R that I am trying to implement.
The program is strcpy with code from KR.
/*strcpy: copy t to s; pointer version 3*/
void strcpy(char *s, char *t){
while(*s++ = *t++)
;
}
So to implement this program, I add
#include<stdio.h>
int main(){
char *s="abc", *t="ABC" ;
strcpy(s,t);
printf("%s\n",t);
printf("%s\n", s);
return 0;
}
However I am getting segmentation error when I run it. I am sure I am missing something but not quite sure what.
Thanks!

char *s="abc", *t="ABC" ;
string literals are not modifiable, however, a char array can be modified, so change it to :
char s[] ="abc", *t="ABC" ;

Literal string values are stored in a read-only memory page; they cannot be modified.

Related

What is the issue with this C code which has a error?

It is a code written to copy one pointer to another.
ERROR is Segmentation error (core Dumped)
#include<stdio.h>
char strcp(char *,char *);
int main()
{
char *p="string",*q;
printf("%s",p);
strcp(p,q);
printf("%s",q);
return 0;
}
char strcp(char *p,char *q)
{
int i;
for(i=0;*(p+i)!='\0';i++)
*(p+i)=*(q+i);
}
char *p="string"...
strcp(p,q);
What p points to is a literal and literals are read-only. Trying to copy anything to it is forbidden (and causes a segmentation fault).
...and q is not initialized, another possible cause of the seg fault.
The problem with this algorithm is an implicit assumption it makes about pointers: char *q is not a string, it is a pointer to character. It can be treated as a string if you allocate space and place a null-terminated sequence of characters into it, but your code does not do it.
You can allocate space to q with malloc, like this:
char *p="string";
char *q=malloc(strlen(p)+1);
In addition, your version of strcpy reads null terminator from a wrong pointer, and does not null-terminate the copied string:
char strcp(char *p, char *q)
{
int i;
for(i=0;*(q+i)!='\0';i++) // <<== Fix this
*(p+i)=*(q+i);
*(p+i) = '\0'; // <<== Add this line
}
As the other answers have indicated the problem starts* with char *p="string",*q;.
The Literal "string" compiles to the equivalent:
const char foo[7] = {'s','t','r','i','n','g','\0'}; why *\0
As you might see further in you code you're trying to copy data to a const a\rray. Which is illegal.
But you're playing C, you have implicitly casted the const char foo[] to a char *p, right there during initialization.
C is not type safe because it's tightly coupled to the actual instruction on the hardware. Where types don't exist anymore, just widths. But that is for another topic.
*It's not the only flaw. I tossed in a few explanatory wiki links. Because the question shows you're a novice programmer. Keep up the work.

char c1[ ]="abcde" works while char *c1="abcde" turns out wrong?

I was working on the "c programming language" exercise2.4, which deletes each character in s1 that matches any character in the string s2.Below is my code, it works. However,if I change the definition in Main function from char c1[ ]="abcde" to char *c1="abcde", it will turns out segmentation fault(core dumped). Any idea why?
#include<stdio.h>
#define UNREPEAT 1
#define REPEAT 0
void squeeze(char *s1,char *s2);
void main(){
char c1[]="abcde";
char c2[]="cd";
printf("c1 is %s\n",c1);
squeeze(c1,c2);
printf("the final result is %s\n",c1);
}
void squeeze(char *s1,char *s2){
int i,j,judge;
int k=0;
for(i=0;*(s1+i)!='\0';i++){
judge=UNREPEAT;
for(j=0;*(s2+j)!='\0';j++){
if (*(s1+i)==*(s2+j)){
judge=REPEAT;
break;}
}
if( judge==UNREPEAT){
* (s1+k)=*(s1+i);
k++;}
}
*(s1+k)='\0';
}
Because
char c1[] = "abcde";
declares an array, it's readable and writable and will always have 6 bytes (if you consider the terminating '\0') you can't extend it but of course you can use it to store less bytes.
While
char *c1 = "abcde";
is a static string literal it shall not be modified, you should always declare string literals using the const qualifier, that way the compiler would warn you if you try to modify its contents, which is illegal, just use
const char *c1 = "abcde";
char *c1="abcde"
This is a string literal which is read-only and in your function you try to change the contents of it so you might hit seg fault.
Whereas the other case
char c1[] = "abcde";
You are allocating memory on the stack whose contents can be modified.
PS: String literals are read-only

Segmentation fault (core dumped) in a simple C code

I am new in C. I am referring to the book "The C Programming Language" by Brian W Kernighian and Dennis Ritchie.
There is a code for pointer increment and assignment given in the book as follows.
#include<stdio.h>
int main()
{
char *s = "Goal";
char *t = "Home";
while(*s++ = *t++) printf(*s);
return 0;
}
The code is saved and compiled using the command
gcc ptr.c -o ptr -std=c99
Now on running the code by running command
./ptr
I get the following error
Segmentation fault (core dumped)
The error seems to be inside the while loop condition.
But the code is exactly as given in the book.
What am I missing?
s and t are both string literals, and you can't modify a string literal. But this piece of code
*s++ = *t++
will modify s, which causes segmentation fault.
To fix it, use a char array. I also modified the printf part to make it legal.
#include<stdio.h>
int main()
{
char arr[] = "Goal";
char *s = arr;
char *t = "Home";
while(*s++ = *t++)
;
printf("%s\n", arr);
return 0;
}
However, I think this program is better done using an individual function to copy the string, the program will look clearer.
#include<stdio.h>
void my_strcpy(char *s, char *t);
int main()
{
char s[] = "Goal";
char *t = "Home";
my_strcpy(s, t);
printf("%s\n", s);
return 0;
}
void my_strcpy(char *s, char *t)
{
while(*s++ = *t++)
;
}
The problem is that printf expects the first parameter to be a char *, that is, something that points to a character, or the address of a character. When you say printf(*s) you're passing it an actual character, i.e. a number from 0 to 255 or -128 to 127, and the program is going to treat that number as an address, which isn't going to be a valid address on your system.
When ever we say *s = "hello" , s is pointing to an address which is present in text segment("hello" goes into text segment). So obviously changing the value of text segment results in SEGV termination.
And for s[] = "hello" if we do *s++, we are incrementing (modifying) the base address so we got "lvalue required as increment operand" error.

C programming strcat using pointer

I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}

Return a pointer to a char array in C

I've seen a lot of questions on that on StackOverflow, but reading the answers did not clear that up for me, probably because I'm a total newbie in C programming. Here's the code:
#include <stdio.h>
char* squeeze(char s[], char c);
main()
{
printf("%s", squeeze("hello", 'o'));
}
char* squeeze(char s[], char c)
{
int i, j;
for(i = j = 0; s[i] != '\0'; i++)
if(s[i] != c)
s[j++] = s[i];
s[j] = '\0';
return s;
}
It compiles and I get segmentation fault when I run it. I've read this faq about about returning arrays and tried the 'static' technique that is suggested there, but still could not get the program working. Could anyone point out exactly what's wrong with it and what should I be paying attention in the future?
The 1st argument passed to the squeeze function is a read-only string literal "hello", which you are trying to modify.
Instead pass it a modifiable char array:
char str[] = "hello";
printf("%s", squeeze(str, 'o'));
The problem is that the constant char array "hello" may not correctly be modified by the function to which it was passed. So, just make sure you're passing a non-constant array (for example by making a local array to be passed, as long as the result is not needed outside of squeeze's caller):
int main()
{
char xxx[] = "hello";
printf("%s", squeeze(xxx, 'o'));
return 0;
}
You'd expect that such a constant could only be passed to a const argument (so that the compiler itself could tell you what you're doing wrong), but, alas, that's not what the C standard mandates (presumably for reasons of backwards compatibility with historical code).
This is trying to modify non-modifiable data.
"hello" is a constant string, stored in memory somewhere. What you're trying to do, then, is change it, and that's generally not allowed. I don't see what you mean by "static", but what you want would be something like...
int main()
{
char hello_str[16];
strcpy(hello_str, "hello");
printf("%s", squeeze(hello_str, 'o'));
}

Resources