strcpy problem with two dimension array in C - c

I'm trying to copy a string to an array of strings using the strcpy function but it doesn't work!
Here is the code:
char *message[10] = { "Hello!000000000000", "Good Bye!", "1202", "hel", "beh", "cheshm" };
char *dst = "Copy";
strcpy(&(message[0]), "Copy");
printf("%s", message[0]);

You have two problems:
strcpy expects a destination argument of type char *. But since message[0] is a char * then &message[0] is a pointer to that pointer which have the type char **. In other words, you pass the wrong pointer as the destination. That leads to undefined behavior.
The second problem happens when you fix the first, and that is you have to remember that literal strings are not modifiable. They are in effect read-only. And you try to copy a string into the literal string that message[0] is pointing to. Attempting to modify a literal string also leads to undefined behavior.
The solution to the second problem is to use an array of arrays of char:
char message[][256] = { ... };
The solution to the first problem is to simply pass message[0]:
strcpy(message[0], "Copy");

The first argument of the strcpy call is not a modifiable array of char, it is the array of char*, producing a type mismatch and unexpected behavior.
Modifying the code to strcpy(message[0], "Copy") would cause another problem as you would be trying to modify the string literal "Hello!000000000000" to which message[0] points.
If you just wish to modify the array element, just use a simple assignment to change the pointer:
char *message[10] = { "Hello!000000000000", "Good Bye!", "1202", "hel", "beh", "cheshm" };
char *dst = "Copy";
message[0] = "Copy";
printf("%s", message[0]);
Note that message is not a 3 dimensional array. It is an array of pointers to char. You could define it as an actual 2D array with the same initializer and the contents would be modifiable:
char message[10][20] = { "Hello!000000000000", "Good Bye!", "1202", "hel", "beh", "cheshm" };
char *dst = "Copy";
strcpy(&(message[0]), "Copy");
printf("%s", message[0]);

Related

what is the relation between these char str[10], char *str and char *str[10] in C?

Can I consider *str[10] as two dimensional array ?
If I declare char *str[10]={"ONE","TWO","THREE"} how we can access single character ?
This record
char str[10];
is a declaration of an array with 10 elements of the type char, For example you can initialize the array like
char str[10] = "ONE";
This initialization is equivalent to
char str[10] = { 'O', 'N', 'E', '\0' };
all elements of the array that are not explicitly initialized are zero-initialized.
And you may change elements of the array like
str[0] = 'o';
or
strcpy( str, "TWO" );
This record
char *str;
declares a pointer to an object of the type char. You can initialize it for example like
char *str = "ONE";
In this case the pointer will be initialize by the address of the first character of the string literal.
This record
char * str[10];
is a declaration of an array of 10 elements that has the pointer type char *.
You can initialize it as for example
char * str[10] = { "ONE", "TWO", "THREE" };
In this case the first three elements of the array will be initialized by addresses of first characters of the string literals specified explicitly. All other elements will be initialized as null pointers.
You may not change the string literals pointed to by elements of the array. Any attempt to change a string literal results in undefined behavior.
To access elements of the string literals using the array you can use for example two subscript operator. For example
for ( sisze_t i = 0; str[0][i] != '\0'; ++i )
{
putchar( str[0][i] );
}
putchar( '\n' );
If you want to change strings then you need to declare for example a two dimensional array like
char str[][10] = { "ONE", "TWO", "THREE" };
In this case you can change elements of the array that are in turn one-dimensional arrays as for example
str[0][0] = 'o';
or
strcpy( str[0], "FOUR" );
Yes: char* str[10]; would create an array of 10 pointers to chars.
To access a single character, we can access it like a 2 dimensional array; i.e.:
char* str[10]={"ONE","TWO","THREE"};
char first = str[0][0];
Can I consider *str[10] as two dimensional array ?
It's unclear what you mean. *str[10] is not a valid type name, and the context is a bit lacking to determine how else to interpret it.
If you mean it as an expression referencing the subsequent definition then no, its type is char, but evaluating it produces undefined behavior.
If you are asking about the type of the object identified by str, referencing the subsequent definition, then again no. In this case it is a one-dimensional array of pointers to char.
If I declare char *str[10]={"ONE","TWO","THREE"} how we can access single character ?
You can access one of the pointers by indexing str, among other other ways. For example, str[1]. You can access one of the characters in the string into which that pointer points by using the indexing operator again, among other ways. For example, str[1][0]. That you are then using a double index does not make str a 2D array. The memory layout is quite different than if you declared, say, char str[3][10];.

Is it applicable to pass pointer to character (after assigning string to it) to method and modify this string after without using array and why not?

I want to pass string to a c function using pointer to char and modify it and it gave me segmentation fault. I don't know why ?
Note*: I know I can pass the string to array of character will solve the problem
I tried to pass it to array of character and pass to function the name of array and it works , but I need to know what the problem of passing the pointer to character.
void convertToLowerCase(char* str){
int i=0;
while(str[i] != '\0')
{
if(str[i]>='A'&& str[i]<='Z'){
str[i]+=32;
}
i++;
}
}
int main(void){
char *str = "AHMEDROSHDY";
convertToLowerCase(str);
}
I expect the output str to be "ahmedroshdy", but the actual output segmentation fault
This (you had char str* which is a syntax error, fixed that):
char *str = "AHMEDROSHDY";
is a pointer to a string literal, thus it cannot be modified, since it is stored in read-only memory.
You modify it here str[i]+=32;, which is not allowed.
Use an array instead, as #xing suggested, i.e. char str[] = "AHMEDROSHDY";.
To be more precise:
char *str = "AHMEDROSHDY";
'str` is a pointer to the string literal. String literals in C are not modifacable
in the C standard:
The behavior is undefined in the following circumstances: ...
The program attempts to modify a string literal

What is the difference between string literals and a pointer?

Generally, you can initialize a pointer with any string literals like char *str = "Hello". I think this means "Hello" returns the address of 'H'. However, the below isn't allowed.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[64];
} Student;
Student initialization(char *str) {
//Student tmp = {}; strcpy(tmp.name, str) //(*1)This is allowed.
//Student tmp = {"Hello"}; //(*2)This is allowed.
Student tmp = {str}; //(*3)This is not allowed.
return tmp;
}
int main(void) {
(...)
}
Could anyone tell me the reason why (*2) is allowed but (*3) is not allowed? Compiling this code makes the error below.
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
Student tmp = {str};
^
All these cases you are trying to initialize a char array. Now after saying that - we can see it makes thing easier. Just like an char array where if we write down a string literal directly it initializes the char array with the content of the string literal.
But in the second case, the string literal which is basically a char array is converted to a pointer to the first element of it (the fist character of string literal) which is then used to initialize the char array. That will not work. Note that, even if str is a pointer to a char array which is not a literal this won't work. For the same reason as specified. Standard allows initialization from the string literal directly. Not other way round.
From standard 6.7.9p14
An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

Building char array from a string (C)

I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:
char * makeArr()
{
static char arr[3];
sprintf(arr, "%s\n", "abc");
return arr;
}
Problems occur when I call this method in main:
int main(int argc, char *argv[])
{
char *arr[3];
arr = makeArr();
return 0;
}
The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.
Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:
char *arr[3];
This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.
Next:
static char arr[3];
sprintf(arr, "%s\n", "abc")
Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.
Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.
I'll try to explain this here briefly, so it's suitable for the Q&A style.
An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.
On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.
In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.
I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.
In an expression, a string literal evaluates to a pointer to the first element.
So, something like this:
char *foo = "bar";
will lead to foo pointing to the b of the array. It's like writing
static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
Among other things, you confused:
char arr[3]; // array of 3 chars.
and,
char *arr[3]; // array of 3 pointers to char.
In main(), you should only write char *arr;
Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.
Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.
Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".
UPDATE:
Assigning a value of char* to the array char arr[10]; seems invalid in C.
You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.
Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference
void makeArr(char arr[]){
sprintf(arr, "%s\n", "abc");
}
Simply pass the existing declared array to the makeArr function...
int main(int argc, char *argv[]) {
char arr[10];
makeArr(arr);
return 0;
}
You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:
#include <stdio.h>
char * makeArr(char *arr)
{
sprintf(arr, "%s\n", "abc");
return arr;
}
int main(int argc, char *argv[])
{
char arr[10];
makeArr(arr);
printf("%s\n", arr);
return 0;
}

How to convert constant char pointer to lower case in C?

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
}

Resources