I have written the following replace function which replaces substring inside a big string as follows:
void replace(char *str1, char *str2, int start, int end)
{
int i,j=0;
for(i=start; i<end; i++, j++)
*(str1+i)=*(str2+j);
}
It works fine when I put a string as replace("Move a mountain", "card", 0,4), but when I declare a string using pointer array like char *list[1]={"Move a mountain"} and pass it to the function as replace(list[0], "card",0,4), it gives me a segmentation fault.
Not able to figure it out. Can anybody please explain this to me?
The code of function replace looks fine, yet all the ways you call it introduce undefined behaviour:
First, with replace("Move a mountain", "card", 0,4), you are passing a string literal as argument for str1, which is modified in replace then. Modifying a string literal is undefined behaviour, and if it "works", it is just luck (more bad luck than good luck, actually).
Second char *list[1]={"Move a mountain"} is similar but introduces another issue: char*list is an array of pointers, and you initialize list[0] to point to string literal ""Move a mountain". So passing list[0] would again lead to UB due to modifying a string literal. But then you pass list[1], which is out of bounds and therefore introduces undefined behaviour. Again, everything can happen, segfaulting being just one such possibility.
Write
char list[] = "Move a mountain"; // copies string literal into a new and modifiable array
replace(list, "card",0,4)
and it should work better.
Related
char *test={"0x11","0x12","0x13","0x00","0x00"};
void change(char* test1, char* test2){
strncpy(test[3], test1, 4);
strncpy(test[4], test2, 4);
}
chage("0x55","0x66");
I can assign the characters to array element directly. However, it will cause the memory leak. That's why I use strncpy() instead.
Please advise if you know how to fix it.
There are at least three two you can get segfault here (one suggestion is to enable compiler warnings - they often pick up "stupid mistakes").
The problem is that test is probably misdeclared, it should probably have been:
char *test[]={"0x11","0x12","0x13","0x00","0x00"};
You initialize a char* with an array of char* which means that you initialize test with the first pointer in that array - which means that test will point to the string literal "0x11", so when you use test[3] as argument to strncpy you will send 1 which is converted to a pointer (probably to address 0x31). strncpy would then try to write to that address which is most probable not allowed. You had nearly a fourth reason here, if you had used test[5] you would asked to access beyond the end of the string which is disallowed (you can access test[4] becase it's the terminating null of the string).
Even if you fix those problems there is a problem because test[3] and test[4] are initialized using a string literal. Then strncpy would try to modify that string literal which is undefined behavior - the segfault is because test[3] and test[4] resides in read-only memory (allowing them to be in read-only memory is one reason why modifying string literals is undefined behavior).
What you instead could have done is to make sure that you have writable copies in test which is maybe not that straight forward in C. One normal solution is to have a function (that you have to call manually) that sets up test, and one that tears it down:
void init_test(void) {
int j;
for(j=0; j<sizeof(test)/sizeof(test[0]); j++)
test[j] = strdup(test[j]);
}
void init_fini(void) {
int j;
for(j=0; j<sizeof(test)/sizeof(test[0]); j++)
free(test[j]);
}
The other answer gives one good reason (never attempt to modify the contents of a string (str(n)cpy does that)).
I'm not even sure you want to represent "characters" as strings, especially as the first declaration doesn't work well (assigning an array of strings to a string).
It will take a lot of work to fix this for sure, but you shall begin by replacing "0x11" by '\x11' (I.E. actually use characters), replace strncpy by mere assignment (true characters are an atomic type which can be assigned directly) and finally change the parameters of the change function to get characters instead of strings.
I was making a basic program of strings and did this. There is a string in this way:
#include<stdio.h>
int main()
{
char str[7]="network";
printf("%s",str);
return 0;
}
It prints network.In my view, it should not print network. Some garbage value should be printed because '\0' does not end this character array. So how it got printed? There were no warning or errors too.
That's because
char str[7]="network";
is the same as
char str[7]={'n','e','t','w','o','r','k'};
str is a valid char array, but not a string, because it's no null-terminated. So it's undefined behavior to use %s to print it.
Reference: C FAQ: Is char a[3] = "abc"; legal? What does it mean?
char str[7]="network";
This Invokes Undefined behavior.
You did not declared array with enough space
This should be
char str[8]="network";
char str[7]="network";
you did not provide enough space for the string
char str[8]="network";
It's possible that stack pages start off completely zeroed in your system, so the string is actually null-terminated in memory, but not thanks to your code.
Try looking at the program in memory using a debugger, reading your platform documentation or printing out the contents of str[7] to get some clues. Doing so invokes undefined behavior but it's irrelevant when you're trying to figure out what your specific compiler and OS are doing at one given point in time.
Given the following code:
#include "stdafx.h"
#include "string.h"
static char *myStaticArray[] = {"HelloOne", "Two", "Three"};
int _tmain(int argc, _TCHAR* argv[])
{
char * p = strstr(myStaticArray[0],"One");
char hello[10];
memset(hello,0,sizeof(hello));
strncpy(hello,"Hello",6);
strncpy(p,"Hello",3); // Access Violation
return 0;
}
I'm getting an access violation at precisely the point when it attempts to write to the address of myStaticArray[0].
Why is this a problem?
Background: I'm porting old C++ to C# as primarily a C# developer, so please excuse my ignorance! This piece of code apparently wasn't an issue in the old build, so I'm confused...
char * p = strstr(myStaticArray[0],"One");
p points to a part of the string literal "HelloOne". You mustn't try to modify string literals, that's undefined behaviour.
Often, string literals are stored in a read-only part of the memory, so trying to write to them causes a segmentation fault/access violation.
static char *myStaticArray[] = {"HelloOne", "Two", "Three"};
The strings in the array are string literals and are non-modifiable in C and in C++.
strncpy(p,"Hello",3);
This function call attempts to modify a string literal.
Another issue is your use of the strncpy function which does not always null terminate the string. This is the case here because strlen("Hello") is greater than 3 (your last strncpy argument).
If you want to be able to modify the strings then you'll need to allocate the character arrays like this
static char myStaticArray[][25] = {"HelloOne", "two", "three"};
The problem, as others stated is that your method causes the compiler create an array of 3 pointers to constant strings. The above declaration creates a two dementional character array, then copies the constant-string data to that memory.
hey guys I need your help. I'm trying to extract a character from a string and set it as the 2nd element of an array of strings. Yet as usual C is giving me segmentation faults, Ive tried sprintf, strcpy, and still segmentation fault the code is:
int getwords(char *line, char *words[])
{
int nwords=2;
char *result= NULL;
char TABS[]="\t";
char spaces[]=" ";
char commas[]=",";
result = strtok(line,TABS);
words[1]=result[strlen(result)-1];//setting the 2nd element of the array to a char
result[strlen(result)-1]='\0';//removing the extracted char from the string
words[0]=result;//setting 1st element to the new modified word
printf("the opcode is:%s and the type is:%c\n",words[0],result[strlen(result)-1]);
return nwords;
}
e.g. If I give it "bye." it should return 2 and an array having 2 elements: 1st elem="bye" 2nd elem="."
I ran some tests and found out that the error is from the statement:
words[1]=result[strlen(result)-1];
Any help is welcom
Are you sure words is a modifiable string?
Literal strings are unmodifiable strings. For example: this gives segmentation fault:
char *test = "forty two";
test[6] = 'T'; /* make two uppercase */
You need to show how you call getwords and the definitions of the variables involved.
I'm guessing you're passing pointers to string literals.
There are two, perhaps four mistakes in the code below, I explain two of the mistakes in the code comments:
If we assume that "line", for the purposes of explaining what happens, is "hey\tthere"...
We also assume that "words" is an array of two pointers to char.
// Find the first token, in this case "hey", and return it in "result".
result = strtok(line,TABS); // NOTE: 'line' has been modified by the function!
// Take the last character in the returned statement, which is 'y', and
// copy it to the second cell in the 'words' array, however we are supposed
// to be copying a *pointer* to char there...
words[1]=result[strlen(result)-1];
Additionally, if "line" is static and can not be changed, the first line above will crash.
If "words" is not allocated or doesn't reference an array of at least two pointers to char, then the second line will crash.
If code execution gets past this point, any code that uses the "words" array will crash because the code will expect pointers, but is getting chars!
char *strtok(char *s1, const char *s2)
repeated calls to this function break string s1 into "tokens"--that is
the string is broken into substrings,
each terminating with a '\0', where
the '\0' replaces any characters
contained in string s2. The first call
uses the string to be tokenized as s1;
subsequent calls use NULL as the first
argument. A pointer to the beginning
of the current token is returned; NULL
is returned if there are no more
tokens.
Hi,
I have been trying to use strtok just now and found out that if I pass in a char* into s1, I get a segmentation fault. If I pass in a char[], strtok works fine.
Why is this?
I googled around and the reason seems to be something about how char* is read only and char[] is writeable. A more thorough explanation would be much appreciated.
What did you initialize the char * to?
If something like
char *text = "foobar";
then you have a pointer to some read-only characters
For
char text[7] = "foobar";
then you have a seven element array of characters that you can do what you like with.
strtok writes into the string you give it - overwriting the separator character with null and keeping a pointer to the rest of the string.
Hence, if you pass it a read-only string, it will attempt to write to it, and you get a segfault.
Also, becasue strtok keeps a reference to the rest of the string, it's not reeentrant - you can use it only on one string at a time. It's best avoided, really - consider strsep(3) instead - see, for example, here: http://www.rt.com/man/strsep.3.html (although that still writes into the string so has the same read-only/segfault issue)
An important point that's inferred but not stated explicitly:
Based on your question, I'm guessing that you're fairly new to programming in C, so I'd like to explain a little more about your situation. Forgive me if I'm mistaken; C can be hard to learn mostly because of subtle misunderstanding in underlying mechanisms so I like to make things as plain as possible.
As you know, when you write out your C program the compiler pre-creates everything for you based on the syntax. When you declare a variable anywhere in your code, e.g.:
int x = 0;
The compiler reads this line of text and says to itself: OK, I need to replace all occurrences in the current code scope of x with a constant reference to a region of memory I've allocated to hold an integer.
When your program is run, this line leads to a new action: I need to set the region of memory that x references to int value 0.
Note the subtle difference here: the memory location that reference point x holds is constant (and cannot be changed). However, the value that x points can be changed. You do it in your code through assignment, e.g. x = 15;. Also note that the single line of code actually amounts to two separate commands to the compiler.
When you have a statement like:
char *name = "Tom";
The compiler's process is like this: OK, I need to replace all occurrences in the current code scope of name with a constant reference to a region of memory I've allocated to hold a char pointer value. And it does so.
But there's that second step, which amounts to this: I need to create a constant array of characters which holds the values 'T', 'o', 'm', and NULL. Then I need to replace the part of the code which says "Tom" with the memory address of that constant string.
When your program is run, the final step occurs: setting the pointer to char's value (which isn't constant) to the memory address of that automatically created string (which is constant).
So a char * is not read-only. Only a const char * is read-only. But your problem in this case isn't that char *s are read-only, it's that your pointer references a read-only regions of memory.
I bring all this up because understanding this issue is the barrier between you looking at the definition of that function from the library and understanding the issue yourself versus having to ask us. And I've somewhat simplified some of the details in the hopes of making the issue more understandable.
I hope this was helpful. ;)
I blame the C standard.
char *s = "abc";
could have been defined to give the same error as
const char *cs = "abc";
char *s = cs;
on grounds that string literals are unmodifiable. But it wasn't, it was defined to compile. Go figure. [Edit: Mike B has gone figured - "const" didn't exist at all in K&R C. ISO C, plus every version of C and C++ since, has wanted to be backward-compatible. So it has to be valid.]
If it had been defined to give an error, then you couldn't have got as far as the segfault, because strtok's first parameter is char*, so the compiler would have prevented you passing in the pointer generated from the literal.
It may be of interest that there was at one time a plan in C++ for this to be deprecated (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0896.asc). But 12 years later I can't persuade either gcc or g++ to give me any kind of warning for assigning a literal to non-const char*, so it isn't all that loudly deprecated.
[Edit: aha: -Wwrite-strings, which isn't included in -Wall or -Wextra]
In brief:
char *s = "HAPPY DAY";
printf("\n %s ", s);
s = "NEW YEAR"; /* Valid */
printf("\n %s ", s);
s[0] = 'c'; /* Invalid */
If you look at your compiler documentation, odds are there is a option you can set to make those strings writable.