This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed last year.
What's wrong with this code?:
int main(int argc, char ** argv) {
char strs[] = "What will be printed?";
char *str1;
char *str2;
strs[5] = '\0';
str1 = strs;
strcpy(str2, str1);
printf("%s\n", str2);
return 1;
}
I want it to print "What", instead i get segmentation fault.
I believe it has something to do with the strcpy(str2, str1);, but what is the explanation for that? The signature of strcpy is char* strcpy(char* destination, const char* source); and that's exactly what i did.
Could you explain that to me?
Your destination string is not initialized - it has no memory reserved for itself. An attempt to write to it causes invalid memory access (you're trying to overwrite something completely random and unplanned) and is followed by a segmentation fault.
One clean way to initialize a string is to define a global macro variable that just sets the largest size of strings you plan on using in your code,
#define MAXBUF 100
Then in your main you can simply write:
char str2[MAXBUF];
And your program will work. Alternative is to use dynamic memory allocation which you will likely learn about soon.
#include <stdio.h>
#include <string.h>
int main() {
char *src = "What will be printed?";
char dest[100];
int START = 0; // start of copy
int LENGTH = 5; // length of copy
// copies up to LENGTH characters from the string pointed to, by src to dest. In a case where the length of src is less than that of LENGTH, the remainder of dest will be padded with null bytes.
strncpy(dest, &src[START], LENGTH);
printf("%s\n", dest);
return 0;
}
Related
This question already has answers here:
Different answers from strlen and sizeof for Pointer & Array based init of String [duplicate]
(4 answers)
Closed 3 years ago.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main()
{
unsigned char str[] = "abcdefg";
unsigned char *str1 = (unsigned char*)malloc(sizeof(str) -1);
memcpy(str1, str, (sizeof(str)-1) );
for(int i = 0; i<(sizeof(str1)); i++)
printf("%c", str1[i]);
free(str1);
}
I want copy the string str to str1 but the output is
abcd
It means that only pointer byte(4byte) is copied.
And i try
printf("%d", sizeof(str)-1 );
it's output is 7
What is my mistake?
it mean that only pointer byte(4byte) is copied.
No, it does not. You're assuming that your printout is correct, which it is not. You can use sizeof on arrays but not on pointers. Well, you can, but it means something different.
Everything is copied. You're just printing the first four characters. Change to:
for(int i = 0; i<(sizeof(str) - 1); i++)
Also, don't cast malloc. Here is why: Do I cast the result of malloc?
First the mistakes and then the correct code:
Mistakes:
Don't ever use sizeof(str) to get the length of the string. It doesn't work with pointers. Instead, use strlen(str) + 1.
You are subtracting 1 from the size of the string on malloc call. Why? You are not making space for the ending NULL character.
When copying strings, if you know that the destination string is large enough to store the source, use strcpy instead of memcpy. If you only want an additional size parameter like in memcpy, use strncpy. memcpy is not meant to deal with strings, but with plain arrays.
The correct type to use for strings is char, not unsigned char.
Not really a mistake, but to print a string you can use printf("%s", str) or puts(str). Why bother with a for loop?
void main() is prohibited by the C standard.
Correct code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[] = "abcdefg";
char str1* = malloc(strlen(str) + 1);
strcpy(str1, str);
puts(str1);
free(str1);
//return 0; - default in C99 and later
}
str1 is a pointer whereas str is a character array. When you say sizeof(str1) in your for loop, it iterates 4 times because sizeof(str1) must have evaluated to 4(a 32 bit compiler) whereas sizeof(str) evaluates to the correct length.
You should read What is the size of a pointer? once to know more about size of pointers.
Fixed code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main()
{
unsigned char str[] = "abcdefg";
unsigned char *str1 = (unsigned char*)malloc(sizeof(str) -1);
memcpy(str1, str, (sizeof(str)-1) );
for(int i = 0; i<(sizeof(str) - 1); i++)
printf("%c", str1[i]);
free(str1);
}
This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 3 years ago.
I'm learning pointers in C, using Linux. I'm trying to use the strcat function, but it doesn't work and I don't understand why.
I'm passing a username to the main as an argument because I need to concatenate and put a number 1 in the first position of this username. For example if the I got as argument username123 I need to convert this to 1username123
I got this code:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
const char *userTemp;
char *finalUser;
userTemp = argv[1]; //I got the argument passed from terminal
finalUser = "1";
strcat(finalUser, userTemp); //To concatenate userTemp to finalUser
printf("User: %s\n",finalUser);
return 0;
}
The code compiles, but I got a segmentation fault error and doesn't know why. Can you please help me going to the right direction?
It is undefined behaviour in C to attempt to modify a string literal (like "1"). Often, these are stored in non-modifiable memory to allow for certain optimisations.
Let's leave aside for the moment the fact that your entire program can be replaced with:
#include <stdio.h>
int main(int argc, char *argv[]){
printf("User: 1%s\n", (argc > 1) ? argv[1] : "");
return 0;
}
The way you ensure you have enough space is to create a buffer big enough to hold whatever you want to do. For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
// Check args provded.
if (argc < 2) {
puts("User: 1");
return 0;
}
// Allocate enough memory ('1' + arg + '\0') and check it worked.
char *buff = malloc(strlen(argv[1]) + 2);
if (buff == NULL) {
fprintf(stderr, "No memory\n");
return 1;
}
// Place data into memory and print.
strcpy(buff, "1");
strcat(buff, argv[1]);
printf("User: %s\n", buff);
// Free memory and return.
free(buff);
return 0;
}
What you shouldn't do is to allocate a fixed size buffer and blindly copy in the data provided by a user. That's how the vast majority of security problems occur, by people overwriting buffers with unexpected data.
I'm trying to use the strcat function, but it doesn't work and I don't understand why.
For starters, you really shouldn't use strcat(). Use strlcat() instead. The "l" version of this and other functions take an extra parameter that let you tell the function how large the destination buffer is, so that the function can avoid writing past the end of the buffer. strcat() doesn't have that parameter, so it relies on you to make sure the buffer is large enough to contain both strings. This is a common source of security problems in C code. The "l" version also makes sure that the resulting string is null-terminated.
The code compiles, but I got a segmentation fault error and doesn't know why.
Here's the prototype for the function: char *strcat( char *dest, const char *src );
Now, you're calling that essentially like this: strcat("1", someString);. That is, you're trying to append someString to "1", which is a string constant. There's no extra room in "1" for whatever string is in someString, and because you're using a function that will happily write past the end of the destination buffer, your code is effectively writing over whatever happens to be in memory next to that string constant.
To fix the problem, you should:
Switch to strlcat().
Use malloc() or some other means to allocate a destination buffer large enough to hold both strings.
Unlike in other languages there is no real string type in C.
You want this:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
const char *userTemp;
char finalUser[100]; // finalUser can contain at most 99 characters
userTemp = argv[1]; //I got the argument passed from terminal
strcpy(finalUser, "1"); // copy "1" into the finalUser buffer
strcat(finalUser, userTemp); //To concatenate userTemp to finalUser
printf("User: %s\n",finalUser);
return 0;
}
or even simpler:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
char finalUser[100]; // finalUser can contain at most 99 characters
strcpy(finalUser, "1"); // copy "1" into the finalUser buffer
strcat(finalUser, argv[1]); //To concatenate argv[1] to finalUser
printf("User: %s\n",finalUser);
return 0;
}
Disclaimer: for the sake of brevity this code contains a fixed size buffer and no check for buffer overflow is done here.
The chapter dealing with strings in your C text book should cover this.
BTW you also should check if the program is invoked with an argument:
int main(int argc, char *arg[]){
if (argc != 2)
{
printf("you need to provide a command line argument\n");
return 1;
}
...
You're missing some fundamentals about C.
finalUser = "1";
This is created in "read-only" memory. You cannot mutate this. The first argument of strcat requires memory allocated for mutation, e.g.
char finalUser[32];
finalUser[0] = '1';
I am trying to copy one string to another using pointers, but stack smashing error occurred, while the string is copied successfully.
Here's the code below,
#include <stdio.h>
void strcat(char *str1, char *str2) {
char *run = str1;
while(*run !='\0')
run++;
while(*str2 !='\0') {
*run = *str2;
run++;
str2++;
}
*run = '\0';
}
int main() {
char s[] = "hellomojo";
char t[] = "world";
printf("\ns :%s", s);
printf("\n t :%s",t);
strcat(s, t);
printf("\ns after:%s",s);
}
Is it due to illegal access to memory not pointed by pointers?
This char s[]="hellomojo"; is basically the same as char s[10]="hellomojo";. It is an array of 10 characters (including the NUL-terminator). You cannot store more than 10 characters in it. But you concatenate the other string with this, writing into illegal memory locations beyond the array. This invokes Undefined Behaviour. Hence the stack smashing problem.
The fix would be to increase the size of the first array like:
char s[32] = "hellomojo"; /* 32 chosen arbitrary */
Working with what little code was supplied, my guess would be that at least one of those char pointers doesn't have enough allocated memory, or does not have a null terminating character as expected.
You show the code, but what is the output and the error message? With more information, it would be easier to debug.
This question already has answers here:
Reverse a string in C solution segfaulting
(2 answers)
Closed 10 years ago.
I have the following code which its main purpose is reverse the characters of a string. So, for example, the string I love cats would be converted to stac evol I.
#include <string.h>
#include <stddef.h>
#include <stdio.h>
void reverseString(char *str)
{
int size = strlen(str);
char *end = str + size - 1;
char tmp;
while (end > str) {
tmp = *str;
*str = *end;
*end = tmp;
end--;
str++;
}
}
int main()
{
char *str = "Y U SEGMENTATION FAULT?";
reverseString(str);
}
When I run this, I get a segmentation fault, and I fail to see why. Also, another question I have is the time complexity (Big O) of this function. I believe it should be O(n/2), since I am not going through all the array but just the half of it. Am I right?
You are trying to modify a character literal, a string in read only data segment. Make a copy/duplicate of it on the heap with strdup, for example:
char *str = strdup("It's OK now");
Or make it a local array (place the string on the stack):
char[] str = "It's OK now";
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
strtok giving Segmentation Fault
I try to use strtok function to split string in many tokens but in this example it returns me a seg. fault error. Where i'm in wrong??
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv){
int i=0;
char * string = "HI:HOW:ARE:YOU:?", *tmp;
while(1){
if(i==0) tmp=strtok(string,":");
else tmp=strtok(NULL,":");
if(tmp==NULL) break;
printf("%s\n",tmp);
i++;
}
return 1;
}
Change
char * string = "HI:HOW:ARE:YOU:?"
for
char string [] = "HI:HOW:ARE:YOU:?"
With char string [] you have an array, and char * you have a pointer. When you declare an array, it will request space to allocate the size of your string. The char * string creates a pointer that points to a literal string.
The problem with char *string it is that the point should not be changed because string literals are typically stored in read-only memory, thus causing undefined behavior 33
( for more detail read this https://www.securecoding.cert.org/confluence/display/seccode/STR30-C.+Do+not+attempt+to+modify+string+literals )
Therefore, since with strtok the contents of the string is modified and broken into smaller strings (tokens) you got problems.