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
Related
I've a function which receives a const char* and I want to convert it to lowercase. But I get the error:
error: array initializer must be an initializer list or string literal
I tried to copy the string variable to another array so that I could lower case it. But I think I've got something confused.
This is my function:
int convert(const char* string)
{
char temp[] = string;
temp = tolower(temp); //error is here
//do stuff
}
I'm struggling to understand what this error means, could someone help in explaining it?
tolower takes a single character and returns it in lowercase.
Even if it didn't, arrays aren't assignable. Arrays and pointers are not the same thing.
You presumably want to do something like:
char *temp = strdup(string); // make a copy
// adjust copy to lowercase
unsigned char *tptr = (unsigned char *)temp;
while(*tptr) {
*tptr = tolower(*tptr);
tptr++;
}
// do things
// release copy
free(temp);
Make sure you understand the difference between the heap and the stack, and the rules affecting string literals.
First of all, tolowertakes char or int, not string.
but even if you passed char, your code wouldn't work, because this error array initializer must be an initializer list or string literal ,means you have to initialize it using one of the following methods:
char arr[4] = {'h', 'e', 'y','\0'}; // initializer list
char arr[4] = "hey"; // string literal
char arr[] = "hey"; // also a string literal
char arr[4];
arr[0] = 'h';
arr[1] = 'e';
arr[2] = 'y';
arr[4] = '\0';
Please note that, tolower() takes a character and not a string:
int tolower ( int c );
Also you are trying to copy the string from string to temp[] variable. There in no overloading of the = operator in C to copy the string into char array.
Now about your error:
error: array initializer must be an initializer list or string literal
It says that the array must be initialized via an list of initial individual items or you can directly assign a string literal.
E.g:
char temp[] = "Hi";
char temp[] = {'H','i','\0'};
Also, check your statement:
temp = tolower(temp);
Here the return type of tolower() is int that you are assigning it to the array temp which is improper.
You can use the following snippet using strlwr():
int convert(const char* string)
{
char *temp= malloc(strlen(string)+1);
strcpy(temp,string);
strlwr(temp);
//do your stuff
}
I'm having trouble changing the contents of a variable holding a string. I'm probably thinking of this too literally compared to an int and not as an array. Maybe have to flush array first?
Much thanks.
// declare with maximum size expected +1 (for terminator 0)
char myString1[20] = "Hello"; //declare and assign one line - OK
myString1[20] = "Hello Longer"; // change contents - fails
myString1[] = "Hello Longer"; // change contents - fails
myString1 = "Hello Longer"; // change contents - fails
This is C, not an object oriented language that takes care of copying strings for you. You'll need to use the string library. For example:
char myString1[20] = "Hello";
strncpy(myString1, "Hello Longer", 20);
You need to use a function like strncpy to copy a string.
In C the assigment operator = does not work for arrays. With the only exception of initialisers.
More over this
myString1[20] = "Hello Longer"
is a type mismatch as myString1[20] is a char to which you obviously only can assign a char or something that can be converted to a char.
To trick this you could do:
#include <stdio.h>
struct Str_s
{
char myString[20];
};
int main(void)
{
struct Str_s str1 = {
"Hello"
};
struct Str_s str2 = {
"World"
};
printf("str1='%s'\nstr2='%s'\n", str1.myString, str2.myString);
str2 = str1;
printf("str1='%s'\nstr2='%s'\n", str1.myString, str2.myString);
return 0;
}
This should print:
Hello World
Hello Hello
Obviously the assignment operator works for structs.
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.
Good evening, I have 2 functions and each of them accepts as argument a pointer to char:
char pointer[255];
func1(char* pointer)
{
...
memcpy(pointer,some_char,strlen(something));
return;
}
func2(char* pointer)
{
...
if (pointer==someother_char) exit(0); //FAILs
//also I have
if(pointer==someother_pointer2char); // FAILs
}
Now I've tried strstr,strcmp etc... doesn't work. Wanted to try memcmp but I don't have static len. As I have to compare char* to char and char* to char* I would be needing two solutions right?
So, how to compare these pointers (actually pointees) in shortest possible way?
Thanks.
E D I T
Thanks to wallacer and Code Monkey now for char* to char comparison I use following:
func1(char* ptr){
char someother_char[255];
char *ptr_char = NULL; //I have to strcmp a few values so this is why I initialize it first
...
ptr_char = someother_char;
if (strcmp(ptr,ptr_char) == 0) //gtfo and it does...
...
ptr_char = some2nd;
if(strcmp...
Any suggestions maybe... (hmm external function for comparing?)
Suggestion1(by Code Monkey)
#include <stdio.h>
int main(void) {
char tempchar[255];
tempchar[0] = 'a';
tempchar[1] = 'b';
tempchar[2] = '\0';
char *ptr_char;
ptr_char = &tempchar[0];
printf("%s", ptr_char);
return 0;
}
You need to use strcmp. Not seeing how you tried to use it, this is how you should use it:
char *someother_char = "a";
char *pointer = "a";
if (strcmp(pointer, someother_char) == 0) { // match!
}
else { // not matched
}
to then do the comparison with a char, you have to promote to a char*:
char *someother_char1;
char test = 'a';
char *pointer = "a";
strncpy((char*)test,someother_char1,sizeof(test));
if (strcmp(pointer, someother_char1) == 0) { // match!
}
else { // not matched
}
if you want to use the char array then you have to de-reference:
char char_array[255];
// don't forget to fill your array
// and add a null-terminating char somewhere, such as char_array[255] = '\0';
char *ptr_somechar = &char_array[0];
char *pointer = "a";
if (strcmp(pointer, ptr_somechar) == 0) { // match!
} else { // not matched
}
Well right off the bat, if you want to compare the pointees, you need to dereference them. This means to compare the actual char value, you'll have to call
if (*pointer == someother_char)
However this will only compare the first char in the array, which is probably not what you want to do.
To compare the whole thing strcmp should work
char* someother_str = "hello strstr";
if(strcmp(pointer, someother_str) == 0) {
// do something
}
Make sure your other string is declared as a char*
More info: http://www.cplusplus.com/reference/clibrary/cstring/strcmp/
Edit: as per your comment. comparing char* and char doesn't really make sense. One is a character value, the other is an address in memory. Do do so, you can either dereference the char* or reference the value variable.
char c;
char* ptr;
// dereference ptr
if ( c == *ptr ) {
...
}
// reference the value
if ( &c == ptr ) {
}
The first method checks if the values are the same. The second checks if ptr is in fact pointing to the memory containing c ie. is ptr a pointer to c
Hope that helps
Use function srtncmp no srtcmp.
int res = strncmp(str, "¿Cuál es tu nombre? ", 100);
See the next link
compare strings
Strings are null terminated. When you use such kind of strings, it's not a good idea to mixing with other memory copy functions.
Once you do the memcpy operation, please note that your destination string will not be null terminated.
memcmp is a fast operations. Otherwise yo can simply loop through each character and quit upon finding a difference.
To use strcmp, please make sure that both the strings are null terminated. Otherwise it will lead to some crash.
I suggest you to use string functions like strcmp,strlen, strcpy to deal with strings because for that it's actually implemented.
You can't compare two pointers unless both pointers are referring to same memory location. Pointer is just a address to a memory location. What you really want to do is that, to compare the contents rather than compare the address where it's stored. So please use strcmp but again I warn you make sure that it's null terminated.
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.