C: String, Array and Pointer? Array failure? - c

I am wondering if one could change the string stored in a variable, without changing the address.
And I am unable to write the code to do this, since when I write codes like
char* A = "abc";
char* B = "def";
A = B; <-- if I write down this code, then A will point to B and address changes.
So does anyone know how to do this, changing the string stored in A to "def" ,without changing the initial address of A?
Moreover, I have tried to change only one word in variable A, again, without changing the address.
To do this, I have write the following failure code. BUT I don't know why it fails.
#include <stdio.h>
#include <string.h>
int main(void)
{
char* s = "ABC";
// print value and address of s.
printf("Value of s is %s \n", s);
printf("Address of s is %p \n", s);
s[0] = 'v';
printf("Value of s is %s \n", s);
printf("Address of s is %p \n", s);
}
Using gdb, I figure out that s[0] = 'v' is invalid and lead to segmentation fault. Why is it the case? Can anyone tell me the reason behind this as well?
Thanks.

This answer is based on a similar one of mine from some time ago.
By declaring a string in the manner you have, you have effectively created a const string that is stored in read only memory.
Short answer:
char A[] = "abc"; // 'A' points to a read-write string, which is 4 characters long { 'a', 'b', 'c', '\0' }
char* B; // 'B' is a pointer that currently points to an unknown area since it isn't initialized
B = A; // 'A' and 'B' now point to the same chunk of memory
char C[] = "abc";
snprintf(C, strlen(C)+1, "def"); // Modify the contents of the area 'C' points to, but don't change what 'C' actually points to.
Long answer:
Consider the example below:
char strGlobal[10] = "Global";
int main(void) {
char* str = "Stack";
char* st2 = "NewStack";
str = str2; // OK
strcpy(str, str2); // Will crash
}
To be safe, you should actually allocate as a pointer to const data to make sure you don't attempt to modify the data.
const char* str = "Stack"; // Same effect as char* str, but the compiler
// now provides additional warnings against doing something dangerous
The first way of allocating memory is static allocation in read-only memory (ie: as with str and str2).
The second allocation is known as dynamic allocation, which allocates memory on the heap, not the stack. The string can be modified without hassle. At some point, you need to free this dynamically allocated memory via the free() command.
There is a third means of allocating a string, which is static allocation on the stack. This allows you to modify the contents of the array which is holding the string, and it is statically allocated.
char str[] = "Stack";
In summary:
Example: Allocation Type: Read/Write: Storage Location:
================================================================================
const char* str = "Stack"; Static Read-only Code segment
char* str = "Stack"; Static Read-only Code segment
char* str = malloc(...); Dynamic Read-write Heap
char str[] = "Stack"; Static Read-write Stack
char strGlobal[10] = "Global"; Static Read-write Data Segment (R/W)

You can change a string only when its content resides in "writable" memory. When you do this
char* A = "abc";
the content of the string A, a string literal, resides in memory that cannot be written. However, if you change the declaration to this
char A[] = "abc";
your string would become writable, and you would be able to copy new content into it:
char A[] = "abc";
char* B = "def";
strcpy(A, B);
The address of the string would remain the same.
One caveat here is that you cannot copy a string into A if its content is longer than that of your original string. To work around this issue, declare A with a specific size, like this:
char A[100] = "abc";
char* B = "quick brown fox jumps over the lazy dog";
strcpy(A, B); // This would work fine

Related

Reveres the string doesn't work in C [duplicate]

I have been struggling for a few hours with all sorts of C tutorials and books related to pointers but what I really want to know is if it's possible to change a char pointer once it's been created.
This is what I have tried:
char *a = "This is a string";
char *b = "new string";
a[2] = b[1]; // Causes a segment fault
*b[2] = b[1]; // This almost seems like it would work but the compiler throws an error.
So is there any way to change the values inside the strings rather than the pointer addresses?
When you write a "string" in your source code, it gets written directly into the executable because that value needs to be known at compile time (there are tools available to pull software apart and find all the plain text strings in them). When you write char *a = "This is a string", the location of "This is a string" is in the executable, and the location a points to, is in the executable. The data in the executable image is read-only.
What you need to do (as the other answers have pointed out) is create that memory in a location that is not read only--on the heap, or in the stack frame. If you declare a local array, then space is made on the stack for each element of that array, and the string literal (which is stored in the executable) is copied to that space in the stack.
char a[] = "This is a string";
you can also copy that data manually by allocating some memory on the heap, and then using strcpy() to copy a string literal into that space.
char *a = malloc(256);
strcpy(a, "This is a string");
Whenever you allocate space using malloc() remember to call free() when you are finished with it (read: memory leak).
Basically, you have to keep track of where your data is. Whenever you write a string in your source, that string is read only (otherwise you would be potentially changing the behavior of the executable--imagine if you wrote char *a = "hello"; and then changed a[0] to 'c'. Then somewhere else wrote printf("hello");. If you were allowed to change the first character of "hello", and your compiler only stored it once (it should), then printf("hello"); would output cello!)
No, you cannot modify it, as the string can be stored in read-only memory. If you want to modify it, you can use an array instead e.g.
char a[] = "This is a string";
Or alternately, you could allocate memory using malloc e.g.
char *a = malloc(100);
strcpy(a, "This is a string");
free(a); // deallocate memory once you've done
A lot of folks get confused about the difference between char* and char[] in conjunction with string literals in C. When you write:
char *foo = "hello world";
...you are actually pointing foo to a constant block of memory (in fact, what the compiler does with "hello world" in this instance is implementation-dependent.)
Using char[] instead tells the compiler that you want to create an array and fill it with the contents, "hello world". foo is the a pointer to the first index of the char array. They both are char pointers, but only char[] will point to a locally allocated and mutable block of memory.
The memory for a & b is not allocated by you. The compiler is free to choose a read-only memory location to store the characters. So if you try to change it may result in seg fault. So I suggest you to create a character array yourself. Something like: char a[10]; strcpy(a, "Hello");
It seems like your question has been answered but now you might wonder why char *a = "String" is stored in read-only memory. Well, it is actually left undefined by the c99 standard but most compilers choose to it this way for instances like:
printf("Hello, World\n");
c99 standard(pdf) [page 130, section 6.7.8]:
The declaration:
char s[] = "abc", t[3] = "abc";
defines "plain" char array objects s and t whose elements are initialized with character string literals.
This declaration is identical to char
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p with type "pointer to char" and initializes it to point to an object with type "array of char" with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
You could also use strdup:
The strdup() function returns a pointer to a new string which is a duplicate of the string s.
Memory for the new string is obtained with malloc(3), and can be freed with free(3).
For you example:
char *a = strdup("stack overflow");
All are good answers explaining why you cannot modify string literals because they are placed in read-only memory. However, when push comes to shove, there is a way to do this. Check out this example:
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int take_me_back_to_DOS_times(const void *ptr, size_t len);
int main()
{
const *data = "Bender is always sober.";
printf("Before: %s\n", data);
if (take_me_back_to_DOS_times(data, sizeof(data)) != 0)
perror("Time machine appears to be broken!");
memcpy((char *)data + 17, "drunk!", 6);
printf("After: %s\n", data);
return 0;
}
int take_me_back_to_DOS_times(const void *ptr, size_t len)
{
int pagesize;
unsigned long long pg_off;
void *page;
pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize < 0)
return -1;
pg_off = (unsigned long long)ptr % (unsigned long long)pagesize;
page = ((char *)ptr - pg_off);
if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
return -1;
return 0;
}
I have written this as part of my somewhat deeper thoughts on const-correctness, which you might find interesting (I hope :)).
Hope it helps. Good Luck!
You need to copy the string into another, not read-only memory buffer and modify it there. Use strncpy() for copying the string, strlen() for detecting string length, malloc() and free() for dynamically allocating a buffer for the new string.
For example (C++ like pseudocode):
int stringLength = strlen( sourceString );
char* newBuffer = malloc( stringLength + 1 );
// you should check if newBuffer is 0 here to test for memory allocaton failure - omitted
strncpy( newBuffer, sourceString, stringLength );
newBuffer[stringLength] = 0;
// you can now modify the contents of newBuffer freely
free( newBuffer );
newBuffer = 0;
char *a = "stack overflow";
char *b = "new string, it's real";
int d = strlen(a);
b = malloc(d * sizeof(char));
b = strcpy(b,a);
printf("%s %s\n", a, b);

Bus error in my own strcat using pointer

I'm doing a pointer version of the strcat function, and this is my code:
void strcat(char *s, char *t);
int main(void) {
char *s = "Hello ";
char *t = "world\n";
strcat(s, t);
return 0;
}
void strcat(char *s, char *t) {
while (*s)
s++;
while ((*s++ = *t++))
;
}
This seems straightforward enough, but it gives bus error when running on my Mac OS 10.10.3. I can't see why...
In your code
char *s = "Hello ";
s points to a string literal which resides in read-only memory location. So, the problem is twofold
Trying to alter the content of the string literal invokes undefined behaviour.
(almost ignoring point 1) The destination pointer does not have enough memory to hold the concatinated final result. Memory overrun. Again undefined behaviour.
You should use an array (which resides in read-write memory) with sufficient length to hold the resulting (final) string instead (no memory overrun).
Suggestion: Don't use the same name for user-defined functions as that of the library functions. use some other name, e.g., my_strcat().
Pseudocode:
#define MAXVAL 512
char s[MAXVAL] = "Hello";
char *t = "world\n"; //are you sure you want the \n at the end?
and then
my_strcat(s, t);
you are adding the text of 't' after the last addres s is pointing to
char *s = "Hello ";
char *t = "world\n";
but writing after 's' is undefined behavior because the compiler might put that text in constant memory, in your case it crashes so it actually does.
you should reserve enough memory where s points to by either using malloc or declare it array style
char s[32] = "Hello ";

When to use char a[] over char p* and vice versa?

Lately I've been learning all about the C language, and am confused as to when to use
char a[];
over
char *p;
when it comes to string manipulation. For instance, I can assign a string to them both like so:
char a[] = "Hello World!";
char *p = "Hello World!";
and view/access them both like:
printf("%s\n", a);
printf("%s\n", p);
and manipulate them both like:
printf("%c\n", &a[6]);
printf("%c\n", &p[6]);
So, what am I missing?
char a[] = "Hello World!";
This allocates modifiable array just big enough to hold the string literal (including terminating NUL char). Then it initializes the array with contents of string literal. If it is a local variable, then this effectively means it does memcpy at runtime, every time the local variable is created.
Use this when you need to modify the string, but don't need to make it bigger.
Also, if you have char *ap = a;, when a goes out of scope ap becomes a dangling pointer. Or, same thing, you can't do return a; when a is local to that function, because return value will be dangling pointer to now destroyed local variables of that function.
Note that using exactly this is rare. Usually you don't want an array with contents from string literal. It's much more common to have something like:
char buf[100]; // contents are undefined
snprintf(buf, sizeof buf, "%s/%s.%d", pathString, nameString, counter);
char *p = "Hello World!";
This defines pointer, and initializes it to point to string literal. Note that string literals are (normally) non-writable, so you really should have this instead:
const char *p = "Hello World!";
Use this when you need pointer to non-modifiable string.
In contrast to a above, if you have const char *p2 = p; or do return p;, these are fine, because pointer points to the string literal in program's constant data, and is valid for the whole execution of the program.
The string literals themselves, text withing double quotes, the actual bytes making up the strings, are created at compile time and normally placed with other constant data within the application. And then string literal in code concretely means address of this constant data blob.
char * strings are read-only. They cannot be modified while char[] strings can be.
char *str = "hello";
str[0] = 't'; // This is an illegal operation
Whereas
char str[] = "hello"; str[0] = 't'; // Legal, string becomes tello

Initializing arrays of type char

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

Is it possible to modify a string of char in C?

I have been struggling for a few hours with all sorts of C tutorials and books related to pointers but what I really want to know is if it's possible to change a char pointer once it's been created.
This is what I have tried:
char *a = "This is a string";
char *b = "new string";
a[2] = b[1]; // Causes a segment fault
*b[2] = b[1]; // This almost seems like it would work but the compiler throws an error.
So is there any way to change the values inside the strings rather than the pointer addresses?
When you write a "string" in your source code, it gets written directly into the executable because that value needs to be known at compile time (there are tools available to pull software apart and find all the plain text strings in them). When you write char *a = "This is a string", the location of "This is a string" is in the executable, and the location a points to, is in the executable. The data in the executable image is read-only.
What you need to do (as the other answers have pointed out) is create that memory in a location that is not read only--on the heap, or in the stack frame. If you declare a local array, then space is made on the stack for each element of that array, and the string literal (which is stored in the executable) is copied to that space in the stack.
char a[] = "This is a string";
you can also copy that data manually by allocating some memory on the heap, and then using strcpy() to copy a string literal into that space.
char *a = malloc(256);
strcpy(a, "This is a string");
Whenever you allocate space using malloc() remember to call free() when you are finished with it (read: memory leak).
Basically, you have to keep track of where your data is. Whenever you write a string in your source, that string is read only (otherwise you would be potentially changing the behavior of the executable--imagine if you wrote char *a = "hello"; and then changed a[0] to 'c'. Then somewhere else wrote printf("hello");. If you were allowed to change the first character of "hello", and your compiler only stored it once (it should), then printf("hello"); would output cello!)
No, you cannot modify it, as the string can be stored in read-only memory. If you want to modify it, you can use an array instead e.g.
char a[] = "This is a string";
Or alternately, you could allocate memory using malloc e.g.
char *a = malloc(100);
strcpy(a, "This is a string");
free(a); // deallocate memory once you've done
A lot of folks get confused about the difference between char* and char[] in conjunction with string literals in C. When you write:
char *foo = "hello world";
...you are actually pointing foo to a constant block of memory (in fact, what the compiler does with "hello world" in this instance is implementation-dependent.)
Using char[] instead tells the compiler that you want to create an array and fill it with the contents, "hello world". foo is the a pointer to the first index of the char array. They both are char pointers, but only char[] will point to a locally allocated and mutable block of memory.
The memory for a & b is not allocated by you. The compiler is free to choose a read-only memory location to store the characters. So if you try to change it may result in seg fault. So I suggest you to create a character array yourself. Something like: char a[10]; strcpy(a, "Hello");
It seems like your question has been answered but now you might wonder why char *a = "String" is stored in read-only memory. Well, it is actually left undefined by the c99 standard but most compilers choose to it this way for instances like:
printf("Hello, World\n");
c99 standard(pdf) [page 130, section 6.7.8]:
The declaration:
char s[] = "abc", t[3] = "abc";
defines "plain" char array objects s and t whose elements are initialized with character string literals.
This declaration is identical to char
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p with type "pointer to char" and initializes it to point to an object with type "array of char" with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
You could also use strdup:
The strdup() function returns a pointer to a new string which is a duplicate of the string s.
Memory for the new string is obtained with malloc(3), and can be freed with free(3).
For you example:
char *a = strdup("stack overflow");
All are good answers explaining why you cannot modify string literals because they are placed in read-only memory. However, when push comes to shove, there is a way to do this. Check out this example:
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int take_me_back_to_DOS_times(const void *ptr, size_t len);
int main()
{
const *data = "Bender is always sober.";
printf("Before: %s\n", data);
if (take_me_back_to_DOS_times(data, sizeof(data)) != 0)
perror("Time machine appears to be broken!");
memcpy((char *)data + 17, "drunk!", 6);
printf("After: %s\n", data);
return 0;
}
int take_me_back_to_DOS_times(const void *ptr, size_t len)
{
int pagesize;
unsigned long long pg_off;
void *page;
pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize < 0)
return -1;
pg_off = (unsigned long long)ptr % (unsigned long long)pagesize;
page = ((char *)ptr - pg_off);
if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
return -1;
return 0;
}
I have written this as part of my somewhat deeper thoughts on const-correctness, which you might find interesting (I hope :)).
Hope it helps. Good Luck!
You need to copy the string into another, not read-only memory buffer and modify it there. Use strncpy() for copying the string, strlen() for detecting string length, malloc() and free() for dynamically allocating a buffer for the new string.
For example (C++ like pseudocode):
int stringLength = strlen( sourceString );
char* newBuffer = malloc( stringLength + 1 );
// you should check if newBuffer is 0 here to test for memory allocaton failure - omitted
strncpy( newBuffer, sourceString, stringLength );
newBuffer[stringLength] = 0;
// you can now modify the contents of newBuffer freely
free( newBuffer );
newBuffer = 0;
char *a = "stack overflow";
char *b = "new string, it's real";
int d = strlen(a);
b = malloc(d * sizeof(char));
b = strcpy(b,a);
printf("%s %s\n", a, b);

Resources