I'm new to C and am having trouble declaring a character array for a class project.
Here's roughly what I'm doing:
char test[]="Test\0";
char *Pointer;
Pointer=test;
I then have a function printString(char* chars) that takes Pointer as an argument. When I try to compile, I'm told that neither test or Pointer are declared. I'm not sure why, so can someone point me in the right direction.
This is the whole code:
main()
{
char *test2="Test\0";
printString(test2);
}
printString(char* charArray)
{
int charPos=0;
int endOfString=1;
char al;
char ah;
int ax;
while(endOfString==1)
{
al=charArray[charPos];
ah=0xE;
ax=ah*256+al;
interrupt(0x10,ax,0,0,0);
if(al=='\0')
{
return 0;
}
charPos++;
}
}
First of all, having the NULL character is not necessary there.
Here is why:
When an array of characters is declared and it is initialize, like in your example:
char test[] = "Test";
The compiler will put the characters from "Test" in the test array, then add a null character so that test can be used as a string like so:
+---+---+---+---+----+
test| T | e | s | t | \0 |
+---+---+---+---+----+
In regards to your question, see if this helps:
void print_string( char *p ) {
while ( *p != '\0' ) {
printf( "%c", *p );
p++;
}
}
Remember a C-style string is a sequence of characters and it's always terminated with NULL character.
The function "print_string", for example, expects a pointer to a char as an argument ( you can past the char array you created, and it will work since arrays are treated as pointers. )
The function will print each character until the NULL character is encountered.
IMPORTANT:
char test[] = "Test";
char *test_2 = "Test";
In the array version, the characters stored in test can be modified, like elements of any array.
In the pointer version, test points to a string literal, and string literals should NOT be modified.
I believe the problem might be because of that, you are trying to modified a string literal. Doing so causes undefined behavior.
Either use an array or allocate memory and make char pointer point to it.
For use your function: printString(char* chars).
declare just:
char *my_string = "Test";
printString(my_string);
The problem is possibly because you don't declare the function before you use it. In C you really have to declare everything before it's used. In this case do e.g.
void printString(char* charArray);
int main(void)
{
...
}
void printString(char* charArray)
{
...
}
Related
In the case down below.
Does changing the string 'out' change the string 'str' respectively? In other words, do they have the same pointer?
Thank you in advance.
int main() {
char str[]={'g','o','o','d','/0'};
char special[]={'o','/0'};
char* out=str;
return 0;
}
It depends. If you write:
out = "hello!";
you do not change the string str, but simply make out point to another memory location.
But if you write into out like in this:
sprintf(out, "abcd");
then you do change str. But beware of overflow!
For starters I think you mean the terminating zero '\0' instead of the multibyte character literal '/0'.
To escape such an error it is better to initialize character arrays with string literals (if you are going to store a string in an array). For example
char str[] = { "good" };
or just like
char str[] = "good";
As for the question then after this assignment
char* out=str;
the pointer out points to the first character of the array str. Thus using this pointer and the pointer arithmetic you can change the array. For example
char str[] = "good";
char *out = str;
out[0] = 'G';
*( out + 3 ) = 'D';
puts( str );
Moreover an array passed as an argument to a function is implicitly converted to pointer to its first character. So you can use interchangeably either an array itself as an argument or a pointer that initialized by the array designator. For example
#include <stdio.h>
#include <string.h>
//...
char str[] = "good";
char *out = str;
size_t n1 = strlen( str );
size_t n2 = strlen( out );
printf( "n1 == n2 is %s\n", n1 == n2 ? "true" : "false" );
The output of this code snippet is true.
However there is one important difference. The size of the array is the number of bytes allocated to all its elements while the size of the pointer usually either equal to 4 or 8 based on used system and does not depend on the number of elements in the array. That is
sizeof( str ) is equal to 5
sizeof( out ) is equal to 4 or 8
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )
I think there's a typo in your code, you have written '/0' but it's not a null character but '\0' is.
As far as out & str are concerned, str[] is a char array, whereas out is a pointer to it. If you make out point to some other char array there'll be no effect on str. But you can use out pointer to change the values inside the str[], like this,
int main( void )
{
char str[]={'g','o','o','d','\0'}; // There was a typo, you wrote '/0', I guess you meant '\0'
//char special[]={'o','\0'};
char* out=str;
for(int i=0; out[i] != '\0'; i++)
{
out[i] = 'a';
// This will write 'a' to the str[]
}
printf("out: %s\n", out);
printf("str: %s", str);
return 0;
}
No. out is a different variable that holds the same address str is at, i.e. it points to the same location. Note that changing *str will change *out.
In C, assignment takes the value of the right end and stores it in the left end, it does not makes the right "become" left
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;
}
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 have used sscanf to scan in a string and add it to a structure. The only problem is that I cannot print out the string because there is no null terminator added by default. I tried to add a null in there with the strcat() function but came to the realization this cannot work. Thanks for any help.
struct a
{
int *ref;
char string[50];
}rec;
void task()
{
char *p_test;
char test[50] = "9999:STRING OF TEXT";
p_test = test;
sscanf(p_test, "%d:%[^\n]", &rec.ref, rec.string);
printf("String is:%s", &rec.string);
}
There are multiple problems with your code.
test[50] = "9999:STRING OF TEXT";
This is wrong for two reasons.
A) test is an array of char, not an array of char*. So, when you assign a string (a char*) to an element, the address is converted to a char.
B) Element 50 does not exist in your array, and writing to it invokes undefined behavior. You have an array of 50 elements with indices 0...49.
To assign an initial value to your array, all you need do is:
char test[50] = "9999:STRING OF TEXT";
And since test does not need to be modified...
const char *test = "9999:STRING OF TEXT";
If you want to zero an array, the simplest method is:
char test[50] = {0};
Of course, you don't need to if you assign the string properly to begin with, and this is not your problem.
Your string member of the a struct is a char, not a char* (a string), and using the %s format specifier when printing it invokes undefined behavior.
main is defined to return int, not void.
sscanf expects pointers to data to fill in. rec.ref is an int, you need to pass its address, i.e., &rec.ref.
You need to allocate storage for rec.string.
Here is a working example:
#include <stdio.h>
#define STRING_LEN 50
struct a
{
int ref;
char string[STRING_LEN];
} rec;
int main()
{
char test[STRING_LEN] = "9999:STRING OF TEXT";
// note that, in the real world, this may
// be a buffer overflow waiting to happen
sscanf(test, "%d:%[^\n]", &rec.ref, rec.string);
printf("String is:%s, rec is:%d", rec.string, rec.ref);
return 0;
}
You have a number of problems; a lack of null-terminator actually isn't one of them.
One problem is a syntax error; this:
char test[50]
test[50] = "9999:STRING OF TEXT";
is not valid syntax. You need:
char test[50] = "9999:STRING OF TEXT";
Another problem is that rec doesn't have a string (a char * or char[]), it just has a single character (a char). A simple approach, to get you started, is:
struct a
{
int ref;
char string[50];
} rec;
A third problem is that sscanf's arguments all have to be pointers. C is a pass-by-value language; if you just pass in an integer, that doesn't give sscanf any way to modify that integer:
sscanf(test, "%d:%[\n]", &rec.ref, rec.string); // (once rec.string is a pointer)
A fourth problem is that the format-specifier %[\n] does not mean what you seem to want it to mean. (Maybe you actually wanted %[^\n]?)
Other, smaller issues include your return-type for main (it should be int, not void).
The common thread with most of these issues is that your compiler would have eagerly helped you identify them, had you simply turned on compiler warnings!
Why is the following code illegal?
typedef struct{
char a[6];
} point;
int main()
{
point p;
p.a = "onetwo";
}
Does it have anything to do with the size of the literal? or is it just illegal to assign a string literal to a char array after it's declared?
It doesn't have anything to do with the size. You cannot assign a string literal to a char array after its been created - you can use it only at the time of definition.
When you do
char a[] = "something";
it creates an array of enough size (including the terminating null) and copies the string to the array. It is not a good practice to specify the array size when you initialize it with a string literal - you might not account for the null character.
When you do
char a[10];
a = "something";
you're trying to assign to the address of the array, which is illegal.
EDIT: as mentioned in other answers, you can do a strcpy/strncpy, but make sure that the array is initialized with the required length.
strcpy(p.a, "12345");//give space for the \0
You can never assign to arrays after they've been created; this is equally illegal:
int foo[4];
int bar[4];
foo = bar;
You need to use pointers, or assign to an index of the array; this is legal:
p.a[0] = 'o';
If you want to leave it an array in the struct, you can use a function like strcpy:
strncpy(p.a, "onetwo", 6);
(note that the char array needs to be big enough to hold the nul-terminator too, so you probably want to make it char a[7] and change the last argument to strncpy to 7)
Arrays are non modifiable lvalues. So you cannot assign to them. Left side of assignment operator must be an modifiable lvalue.
However you can initialize an array when it is defined.
For example :
char a[] = "Hello World" ;// this is legal
char a[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};//this is also legal
//but
char a[20];
a = "Hello World" ;// is illegal
However you can use strncpy(a, "Hello World",20);
As other answers have already pointed out, you can only initialise a character array with a string literal, you cannot assign a string literal to a character array. However, structs (even those that contain character arrays) are another kettle of fish.
I would not recommend doing this in an actual program, but this demonstrates that although arrays types cannot be assigned to, structs containing array types can be.
typedef struct
{
char value[100];
} string;
int main()
{
string a = {"hello"};
a = (string){"another string!"}; // overwrite value with a new string
puts(a.value);
string b = {"a NEW string"};
b = a; // override with the value of another "string" struct
puts(b.value); // prints "another string!" again
}
So, in your original example, the following code should compile fine:
typedef struct{
char a[6];
} point;
int main()
{
point p;
// note that only 5 characters + 1 for '\0' will fit in a char[6] array.
p = (point){"onetw"};
}
Note that in order to store the string "onetwo" in your array, it has to be of length [7] and not as written in the question. The extra character is for storing the '\0' terminator.
No strcpy or C99 compund literal is needed. The example in pure ANSI C:
typedef struct{
char a[6];
} point;
int main()
{
point p;
*(point*)p.a = *(point*)"onetwo";
fwrite(p.a,6,1,stdout);fflush(stdout);
return 0;
}