I'm starting to learn C and I'm a little bit confuse with c string pointer.
int argc = 0;
const char *str[] = { "hello" , NULL, NULL };
str[argc++] = "nice!";
str[argc++] = "abc";
str[argc++] = "def"
send_args(argc, str);
//the prototype/header : int send_args(int argc, const char **args);
because send_args function doesn't modify the value of passed str, are those operation valid?
because I don't want to do something like :
int i, argc = 0;
char *str[3];
str[argc++] = strdup("nice!");
str[argc++] = strdup("abc");
str[argc++] = strduo("def)"
send_args(argc, str);
for (i = 0; i< argc; i++)
if (str[i]) { free(str[i]); str[i]=NULL; }
Thanks in advance guys.
I see nothing wrong with the first example.
Yes, that's alright. The string literals are likely placed in the initialized data section (details are implementation defined) and there is no need (in fact, not even a possibility) to free literals.
The type of str is compatible with the one required by send_args, so all is fine.
Note that as written, str[] is initialized with three elements and thus cannot hold four or more pointers. You could achieve the same effect with a declaration and initialization like
const char *str[3];
str[0] = "nice!";
str[1] = "abc";
str[2] = "def"
send_args(3, str);
Yes, they are perfectly valid. You need to be concerned about argc though because you are incrementing it one more than needed. It would not cause any "undesirable effects" as far as you are handling it correctly. You can check your code's example here
If you're asking about automatic storage duration, your str array won't be destroyed until execution reaches the end of the block it was created within.
const char **fubar(void)
{
int argc = 0;
const char *str[] = { "hello" , NULL, NULL }; /* str is created here */
str[argc++] = "nice!";
str[argc++] = "abc";
str[argc++] = "def"
send_args(argc, str); /* the lifetime of str is still valid here */
return str; /* ... but str gets destroyed after this "return" statement */
}
int main(void) {
const char **fubared = fubar();
/* str has already been destroyed, and fubar's return value has been rendered garbage */
/* so using fubared would be a bad idea. */
return 0;
}
return causes str to be destroyed, because execution has surpassed the end of the block it was created within, and the pointer being returned would point to garbage.
In this case they are valid, because the strings are stored statically at compile time and cannot be freed. Their pointer addresses also do not depend on the function you are in.
But if you would use a local char array for "nice!", it would not be valid, because the send_args cannot read local variables of other functions.
Related
I've been giving an... interesting... task. I've been asked to modify a character array using a pointer.
I'm aware that:
*char = "something"; //is a literal and cannot be modified.
char[] = "something"; //can be modified
But what about:
main.c
------
static char* stringlist01[] =
{
"thiy iy a ytring",
"this is also a string, unlike the first string",
"another one, not a great one, and not really like the last two.",
"a third string!",
NULL,
};
int main()
{
int ret = 9999;
printf("////TEST ONE////\n\n");
ret = changeLetterInString(stringlist01[0]);
printf("Return is: %d\n\n", ret);
printf("Stringlist01[0] is now: %s\n", stringlist01[0]);
}
AND
changeLetterInString.c
----------------------
int changeLetterInString(char *sentence)
{
if (sentence != NULL)
{
// TODO
// Need to change "thiy iy a ytring"
// into "this is a string"
// and save into same location so
// main.c can see it.
}
success = 0; // 0 is Good
return success;
}
So far, I've tried:
for (char* p = sentence; *p; ++p)
{
if (*p == 'y')
{
*p = 's';
}
}
And I've tried:
sentence[0] = 't'
sentence[1] = 'h'
sentence[2] = 'i'
sentence[3] = 's' // and so on...
But neither work.
Any help and/or insight would be greatly appreciated.
There are subtle differences between the two notations:
char string[] = "Hello World";
// vs
char* string = "Hello World";
They look similar enough, right? However they are different. The first one is an array of characters, whereas the second one is a pointer to an array of characters.
By default, any string literal will always be const. No way around it. Trying to modify a string literal will usually result in a segfault.
Your code contains an array of pointers to an array of characters. Since you contain pointer references to constant string literals, you cannot modify them. In order to modify them, you need to convert them into an array instead, like how it's done in the first example. This will transform the string literal to an array of characters, that can be modified, rather than being a pointer to memory which cannot be modified.
char strs[][] = {
"Hello",
"World"
}; // transforms the string literals into character arrays
strs[0][0] = 'X'; // valid
Whereas this would not compile, and caused undefined behaviour
char* strs[] = {
"Hello",
"World",
};
strs[0][0] = 'X'; // trying to modify a pointer to a constant string literal, undefined
int string1()
{
char str[]="something"
}
int string2()
{
//here I need use array str[] from string1
}
how can I use array value? Im doing string operations
Everyone has to learn how to use arrays, strings, pointers and functions -- and how to pass arrays and pointers to functions and handle function returns.
When you declare a variable (including an array type), the lifetime for the variable exists only within the scope it is declared unless memory for the variable is allocated dynamically or it is declared as static or otherwise has static storage duration.
Why? Storage for variables declared within a function is created on the function stack which is destroyed (released for reuse) on the function return. (main() is itself a function). Now a function can always return a value of its own type, but it cannot declare a an array of type with automatic storage within the function and return a pointer to the array.
char str[]="something"; /* violates that rule.... */
You have a few options, but they rely on understanding the storage duration for "something" and exactly what it is. let's look at what it appears you are attempting to do:
/* retuning pointer to string literal */
const char *string1 ()
{
const char *s = "something";
return s;
}
There are a few subtleties above. First "something" is a string literal and it has static storage duration for the life of the program. So you are assigning the address of "something" that is created in read-only memory that will survive the return of string1. Since a function can always return it's own type (in this case const char * -- chosen for that purpose), you can return the address to "something".
To use s in string2, you must pass s as an argument to string2, or assign the return of string1 to a global pointer (discouraged). Since s points to read-only memory, you should declare the parameter passed to string2 as const char * to signal it cannot be modified. Something similar to:
/* simply use string 's' in string2 */
void string2 (const char *s)
{
printf ("in string2(), s : %s\n", s);
}
Putting it altogether, you could do something like the following:
#include <stdio.h>
/* retuning pointer to string literal */
const char *string1 ()
{
const char *s = "something";
return s;
}
/* simply use string 's' in string2 */
void string2 (const char *s)
{
printf ("in string2(), s : %s\n", s);
}
int main (void) {
/* call string 2 passing string1 as the parameter */
string2 (string1 ());
return 0;
}
Example Use/Output
$ ./bin/literalreturn
in string2(), s : something
note: you can only get away with returning s in string1 because of the string literal static storage duration. Otherwise, you would need to pass s as a parameter to string1 or dynamically allocate storage for s within string1 and return a pointer to the starting address for the new block of memory.
If you were passing a character array to string1, then you would need to do something similar to the following:
#include <stdio.h>
#include <string.h>
#define MAXC 32 /* constant for array size */
/* anytime you are passing an array, pass the size. */
char *string1 (char *s, size_t max)
{
if (max < 2) {
fprintf (stderr, "error: insufficient max size.\n");
return NULL;
}
if (strlen (s) < max - 1)
strcpy (s, "something");
return s;
}
/* simply use string 's' */
void string2 (const char *s)
{
printf ("in string2(), s : %s\n", s);
}
int main (void) {
char buf[MAXC] = ""; /* declare character array of MAXC chars */
/* call string 2 passing string1 passing array and size */
string2 (string1 (buf, sizeof buf));
return 0;
}
(Since s isn't changed in string2 it is still properly passed as const char *s which allows certain compiler optimizations for your code.)
Look things over. You must understand the subtleties of each example as these concepts underlie much of C. Let me know if you have further questions.
You can use static variable in the function definition block, this has the global storage but limited access scope, when need to access it, just through the function call to get the pointer. Below is the code:
char* string1() {
static char s[64] = "hello"; //this memory has 64 chars
return s;
}
int main(int argc , char *argv[])
{
char* s = string1();
int len = strlen(s);
printf("len: %d\n", len);
for (int i = 0; i < len; ++i) {
printf("char at: %d is %c\n", i, s[i]);
}
}
Output:
len: 5
char at: 0 is h
char at: 1 is e
char at: 2 is l
char at: 3 is l
char at: 4 is o
You can't. The string from the first function is a local variable and accessing it out of scope leads to undefined behavior. What you could do is allocate the string dynamically and hand control over it to the user.
If your str is a constant as in
char str[]="something";
it is a string literal you could simply return str which being an array, will decay into base address of the array because it would be in read only memory and will remain there till end of program.
If this is the case the return type of the function should be char * like
char *string1();
See demo.
If the str is not so,
char str[30];
strcpy(str, "hello");
the str would be allocated in the stack and it cannot be accessed once control exits the function in which it is declared.
To circumvent this, you could allocate on heap memory like
char *string1()
{
char *str=malloc(sizeof(char)*30);
strcpy(str, "hello");
return str;
}
And don't forget to deallocate the memory once you are done using it.
char *p=string1();
printf("\n%s", p);
free(p);
See demo.
If I want to return an empty char*, I can do this
char* Fun1(void) {
return "";
}
Now imagine the same problem with char**, I want to return an empty array of char*.
Is there a shorter way to write this without using a temporary variable ?
char** Fun2(void) {
char* temp[1] = {""};
return temp;
// return {""}; // syntax error !
}
The goal is to hide the fact that the string can be a NULL pointer.
The equivalent to what you did with the string literal would be something like this:
char const* const* Fun2(void) {
static char const* const tmp[] = {""};
return tmp;
}
But as I said in a comment to the question, you might need to re-think what "empty" means.
You also need to consider what you're going to do if there are cases where the return isn't empty. If the caller is supposed to free the returned pointer, then returning pointers to string literals and/or static arrays is out.
Don't use a temporary variable, as it will be out of scope on return. If you have multiple functions that return the same empty array, they can return pointers to the same 'empty array'.
char* EmptyArray[1] = {""};
char** Fun2(void)
{
return EmptyArray;
}
Also, this makes it easy to detect if the function specifically returned emptiness, by comparing pointers:-
char **arr = Fun2();
if (arr == EmptyArray)
...
Firstly, it is not a good idea to return pointers from functions that have just been allocated. The problem is that the user then has to free that memory, and so you are forcing them to use the same memory management function as you are.
With that in mind, you want to allocate 2 bits of memory here: one for the pointer to a character and another for the character itself.
char** p = malloc(sizeof(*p));
*p = malloc(sizeof(**p));
**p = '\0';
return p;
And then remember the user then has to do:
free(*p);
free(p);
But I will say again, what you are doing is not good programming. You are better off writing functions that accept a null pointer.
the {""} only can be used to initial the variable at its definition. but not as an expression, that is, you can't use it like
char* temp[1];
temp = {""}; // invalid
The first case is fine, a string literal such as "" is safe to return from a function. For the second case, where you need an array of length 1 that contains a pointer to an empty string, you could do some trickery:
char ** array_empty_if_null(const char **array)
{
static char *empty[] = { "" };
return (array == NULL || array[0] == NULL) ? empty : array;
}
I think this matches your description of what you need.
Can't you just return null, because null is empty pointer?
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.
I know this has been asked thousands of times but I just can't find the error in my code. Could someone kindly point out what I'm doing wrong?
#include <stdlib.h>
#include <string.h>
void reverseString(char *myString){
char temp;
int len = strlen(myString);
char *left = myString;
// char *right = &myString[len-1];
char *right = myString + strlen(myString) - 1;
while(left < right){
temp = *left;
*left = *right; // this line seems to be causing a segfault
*right = temp;
left++;
right--;
}
}
int main(void){
char *somestring = "hello";
printf("%s\n", somestring);
reverseString(somestring);
printf("%s", somestring);
}
Ultimately, it would be cleaner to reverse it in place, like so:
#include <stdio.h>
#include <string.h>
void
reverse(char *s)
{
int a, b, c;
for (b = 0, c = strlen(s) - 1; b < c; b++, c--) {
a = s[b];
s[b] = s[c];
s[c] = a;
}
return;
}
int main(void)
{
char string[] = "hello";
printf("%s\n", string);
reverse(string);
printf("%s\n", string);
return 0;
}
Your solution is essentially a semantically larger version of this one. Understand the difference between a pointer and an array. The standard explicitly states that the behviour of such an operation (modification of the contents of a string literal) is undefined. You should also see this excerpt from eskimo:
When you initialize a character array with a string constant:
char string[] = "Hello, world!";
you end up with an array containing the string, and you can modify the array's contents to your heart's content:
string[0] = 'J';
However, it's possible to use string constants (the formal term is string literals) at other places in your code. Since they're arrays, the compiler generates pointers to their first elements when they're used in expressions, as usual. That is, if you say
char *p1 = "Hello";
int len = strlen("world");
it's almost as if you'd said
char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);
Here, the arrays named internal_string_1 and internal_string_2 are supposed to suggest the fact that the compiler is actually generating little temporary arrays every time you use a string constant in your code. However, the subtle fact is that the arrays which are ``behind'' the string constants are not necessarily modifiable. In particular, the compiler may store them in read-only-memory. Therefore, if you write
char *p3 = "Hello, world!";
p3[0] = 'J';
your program may crash, because it may try to store a value (in this case, the character 'J') into nonwritable memory.
The moral is that whenever you're building or modifying strings, you have to make sure that the memory you're building or modifying them in is writable. That memory should either be an array you've allocated, or some memory which you've dynamically allocated by the techniques which we'll see in the next chapter. Make sure that no part of your program will ever try to modify a string which is actually one of the unnamed, unwritable arrays which the compiler generated for you in response to one of your string constants. (The only exception is array initialization, because if you write to such an array, you're writing to the array, not to the string literal which you used to initialize the array.) "
the problem is here
char *somestring = "hello";
somestring points to the string literal "hello". the C++ standard doesn't gurantee this, but on most machines, this will be read-only data, so you won't be allowed to modify it.
declare it this way instead
char somestring[] = "hello";
You are invoking Undefined Behavior by trying to modify a potentially read-only memory area (string literals are implicitly const -- it's ok to read them but not to write them). Create a new string and return it, or pass a large enough buffer and write the reversed string to it.
You can use the following code
#include<stdio.h>
#include<string.h>
#include<malloc.h>
char * reverse(char*);
int main()
{
char* string = "hello";
printf("The reverse string is : %s", reverse(string));
return 0;
}
char * reverse(char* string)
{
int var=strlen(string)-1;
int i,k;
char *array;
array=malloc(100);
for(i=var,k=0;i>=0;i--)
{
array[k]=string[i];
k++;
}
return array;
}
I take it calling strrev() is out of the question?
Your logic seems correct. Instead of using pointers, it is cleaner to deal with char[].