Zero length array works,and i can't change it - c

I discovered mistake in my code (C). I declared zero length array,and it works.Problem is I don't know is that dangerous? I tried change it to
char c[1];
c[0] = '\0'; //or char c[1] = {""};
but then it does not work. There is my code:
void TranslateFile(struct keyElem* guard,FILE* inpFile,FILE* outFile)//"tłumaczy" plik spowrotem
{
char x;
char c[0] = {""};
char tab[100] = {""};
char empty[100] = {""};
while((feof(inpFile)==0))
{
fscanf(inpFile,"%c",&x);
if(x==' ')
{
c[0] = SearchChar(guard,tab);//get char from list
fprintf(outFile,"%s",c);
strcpy(tab,empty);
x = '\0'; //puts(tab);
}
if(x != ' ')
{
c[0] = x;
strcat(tab,c);
}
}
}
I dont know is it save or not and i dont know how to change it.

Zero length array should not be allowed. Which compiler do you user?
Use %c instead of %s in fprintf. %s needs a zero terminated char*, but your code has a char[1]. it might work in debug build when C[1] is '/0'. But in release version, the program may write a very long string into the output file until there is a '/0' in memory. If you must use a char array, declare a char[2] and set c[1] = '\0' in all cases.
"if (x != ' ')" logic is a bit strange. You have x = '\0' in the first if.

The standard doesn't allow it:
If the expression is a constant expression, it shall have a value
greater than zero. Array Declarations - From the standrad
However, GCC Allows it:
Non-empty initialization of zero-length arrays is treated like any
case where there are more initializer elements than the array holds,
in that a suitable warning about “excess elements in array” is given,
and the excess elements (all of them, in this case) are ignored. GCC - Arrays of Length Zero
So at best, all initialization values are ignored and you can't use that array in any practical way.

Ok I fixed it like user #wyc said.I wrote
void TranslateFile(struct keyElem* guard,FILE* inpFile,FILE* outFile)//"tłumaczy" plik spowrotem
{
char x;
char c[2] = {'\0','\0'};
char tab[100] = {""};
char empty[100] = {""};
while((feof(inpFile)==0))
{
fscanf(inpFile,"%c",&x);
if(x==' ')
{
c[0] = SearchChar(guard,tab);
fprintf(outFile,"%c",c[0]);
strcpy(tab,empty);
x = '\0';
printf("[%s]\n",c);
}
if(x != ' ')
{
c[0] = x;
strcat(tab,c);
}
}
}
and it works exactly.Thanks all of you for helpfull answers.Im begginer so i havent intuition for it yet;)

Related

Assigning char to char* using pointers

Let's say I have a char *str and I want to assign it characters one by time using using pointers and incrementing ?
I've done :
char *str;
char c = 'a';
*str++ = c;
But it doesn't work.
How can I do that ?
str is just a pointer. It doesn't point anywhere valid (especially not to some memory you could write to). A simple possibility would be to have it point to an array:
char buf[1024] = {0}; // room for 1024 chars (or 1023 + a 0 byte for a string)
char *str = buf;
char c = 'a';
*str++ = c;
char *str is a pointer to a char (or an array of chars), however, you never assigned it. As has been mentioned earlier a char * basically says "go there" but there is no there there, you never gave it a value. You first need to use malloc to create space to put things in. Here's an example
char *str = malloc(sizeof(char)*10) //allocate space for 10 chars
char c = 'a';
str[0] = c;
no error check was made to malloc which you should do in your own program. You can also do it as such
char str[10];
char c = 'a';
str[0] = c;
however with this method you will be restricted to 10 chars and you cannot change that amount, with the previous method you can use realloc to get more or less space in your array.
But it doesn't work.
char* str;
... is not initialized to anything, therefore dereferencing it is to undefined behaviour. If it where initialized, then in expression *str++ = c; str++ is a post-increment operator, which returns a copy of the pointer whilst incrementing the original. The effect is that the copy points to the previous, and therefore what is pointed to by the previous pointer is assigned c.
To which part that doesn't work are you referring?
EDIT:
As mentioned in one of the comments, a copy is not really returned but the value is increment in place after having been evaluated.
As a variable with automatic storage duration the pointer str has indeterminate value. If even it had the static storage duration its value would be NULL. So you may not use such a pointer to store data.
What you mean can look for example the following way
#include <stdio.h>
int main( void )
{
char s[11];
char *p = s;
while (p != s + sizeof( s ) / sizeof( *s ) - 1 ) *p++ = 'a';
*p = '\0';
puts(s);
return 0;
}
The program output is
aaaaaaaaaa
Here in the program the pointer p of the type char * is initialized by the address of the first character of the array s.
Thus this statement used in the loop
*p++ = 'a';
fills sequentially the array with the character 'a'.
The next example is more interesting
#include <stdio.h>
char * copy_string(char *dsn, const char *src)
{
for (char *p = dsn; (*p++ = *src++) != '\0'; )
{
// empty body
}
return dsn;
}
int main( void )
{
char *src = "Hi QBl";
char dsn[7];
puts(copy_string(dsn, src));
return 0;
}
The program output is
Hi QBl
Here is a demonstration of a function that copies one character array containing a string into another character array using pointers.

change string in c with only pointer

There is pointer to string let say: char *p = "abcdef"
I want to delete some of the chars.
Let say every second char, so i want to get *p="ace"
my algorithm is something like:
int i=1,j=1
for(;p != '\0';p++,i++)
if (i % 2 ==0)
*(p - j++)= *p
*(p-j)='\0'
This algorithm is find the every second char of course but not matter how I try to write the "delete" process or there are compilation errors or the string is unchanged.
I start to believe there is no way to solve that issue without any malloc help.
Again i need to do it on O(n) without any other STRINGS arrays.
p != '\0' should be *p != '\0'(or *p != 0 or *p).
i should be initialized to 0. (You are keeping the wrong ones.)
j should be initialized to 0. (Off by one error.)
j needs to be incremented each time p is incremented.
Your code would be more readable and less fragile if you avoided offsets relative to an unrelated pointer.
void filter_inplace(char* src) {
char* dst = src;
for (size_t i=0; src[i]; ++i) {
if (i % 2 == 0)
*(dst++) = src[i];
}
*dst = 0;
}
Alternative:
void filter_inplace(char* src) {
char* dst = src;
while (1) {
if (!*src) break;
*(dst++) = *(src++);
if (!*src) break;
src++;
}
*dst = 0;
}
Of course, you can't do the following because p points to read-only memory:
char* p = "abcdef"; # XXX Should be "const char*".
filter_inplace(p); # XXX Overwrites read-only memory.
You could do the following:
char p[] = "abcdef";
filter_inplace(p);
You could do the following:
char* p = strdup("abcdef");
filter_inplace(p);
free(p);
I start to believe there is no way to solve that issue without any malloc help. Again i need to do it on O(n) without any other STRINGS arrays.
Kind of true. At least it is true that it can't be done without another string. Even if you used malloc (or strdup) for getting memory I would still consider it another string.
So as long a you initialize the char pointer like:
char *p = "abcdef";
it can not be done. You can't change any character in the string "abcdef".
If the above code was changed to
char p[] = "abcdef";
you would be able to do what you a trying. But even this could be considered as using another string as you have both the initializer string and char array.

Convert Char to String in C

How do I convert a character to a string in C. I'm currently using c = fgetc(fp) which returns a character. But I need a string to be used in strcpy
To answer the question without reading too much else into it I would
char str[2] = "\0"; /* gives {\0, \0} */
str[0] = fgetc(fp);
You could use the second line in a loop with whatever other string operations you want to keep using chars as strings.
You could do many of the given answers, but if you just want to do it to be able to use it with strcpy, then you could do the following:
...
strcpy( ... , (char[2]) { (char) c, '\0' } );
...
The (char[2]) { (char) c, '\0' } part will temporarily generate null-terminated string out of a character c.
This way you could avoid creating new variables for something that you already have in your hands, provided that you'll only need that single-character string just once.
Using fgetc(fp) only to be able to call strcpy(buffer,c); doesn't seem right.
You could simply build this buffer on your own:
char buffer[MAX_SIZE_OF_MY_BUFFER];
int i = 0;
char ch;
while (i < MAX_SIZE_OF_MY_BUFFER - 1 && (ch = fgetc(fp)) != EOF) {
buffer[i++] = ch;
}
buffer[i] = '\0'; // terminating character
Note that this relies on the fact that you will read less than MAX_SIZE_OF_MY_BUFFER characters
I use this to convert char to string (an example) :
char c = 'A';
char str1[2] = {c , '\0'};
char str2[5] = "";
strcpy(str2,str1);
A code like that should work:
int i = 0;
char string[256], c;
while(i < 256 - 1 && (c = fgetc(fp) != EOF)) //Keep space for the final \0
{
string[i++] = c;
}
string[i] = '\0';
//example
char character;//to be scanned
char merge[2];// this is just temporary array to merge with
merge[0] = character;
merge[1] = '\0';
//now you have changed it into a string
This is an old question, but I'd say none of the answers really fits the OP's question. All he wanted/needed to do is this:
char c = std::fgetc(fp);
std::strcpy(buffer, &c);
The relevant aspect here is the fact, that the second argument of strcpy() doesn't need to be a char array / c-string. In fact, none of the arguments is a char or char array at all. They are both char pointers:
strcpy(char* dest, const char* src);
dest : A non-const char pointer
Its value has to be the memory address of an element of a writable char array (with at least one more element after that).
src : A const char pointerIts value can be the address of a single char, or of an element in a char array. That array must contain the special character \0 within its remaining elements (starting with src), to mark the end of the c-string that should be copied.
Here is a working exemple :
printf("-%s-", (char[2]){'A', 0});
This will display -A-
FYI you dont have string datatype in C. Use array of characters to store the value and manipulate it. Change your variable c into an array of characters and use it inside a loop to get values.
char c[10];
int i=0;
while(i!=10)
{
c[i]=fgetc(fp);
i++;
}
The other way to do is to use pointers and allocate memory dynamically and assign values.

How to loop through a string created by pointer

What I want to do is to iterate through the quote till the end of the quote/(*quote has nothing in it). Is my code valid?
char *quote = "To be or not to be, that is the question.";
for (quote = 0; *quote != NULL; quote++){
*quote = tolower(*quote);
}
You probably need another pointer to traverse the array, otherwise access to your original string will be lost.
And preferably only use NULL for pointers.
Don't use 0 as the initial value, unless you want to use indices instead (see below).
Doing char *quote = will simply make quote point to the read-only literal, instead of copying the string. Use char quote[] = instead.
char quote[] = "To be or not to be, that is the question.";
char *quotePtr;
for (quotePtr = quote; *quotePtr != '\0'; quotePtr++){
*quotePtr = tolower(*quotePtr);
}
Test.
Using indices:
char quote[] = "To be or not to be, that is the question.";
int i;
for (i = 0; quote[i] != '\0'; i++){
quote[i] = tolower(quote[i]);
}
Test.
Consider this as an expansion to the answer given by Dukeling
When you use
char *quote = "Hello World";
This makes a read-only string, means that you can't change its contents in a simpler way.
Here *quote points to 'H'
BUT, you cannot do *quote = 'A';
This will give you an error.
If you wish to make changes to the characters in a string, it is a good habit to use arrays.
char quote[] = "Hello World";
Here also *quote points to 'H'
BUT, in this case *quote = 'A' is perfectly valid.
The array quote will get changed.
You're reassigning quote in your for initializer, which is invalid and will cause an access-violation because you're dereferencing it in the *quote != NULL part.
Semantically NULL and '\0' are equivalent, but syntactically I'd prefer this. Note that by using this approach you keep a pointer to (the start of) the string.
wchar const_t* quote = L"To be or not to be, that is the question.";
for( wchar_t* c = quote; *c != '\0'; c++ ) {
*c = tolower( *c );
}
alternatively using an index:
wchar const_t quote[] = L"To be or not to be, that is the question.";
for( size_t i = 0; i < sizeof(quote); i++ ) {
quote[i] = tolower( quote[i] );
}
(note that the semantics of sizeof will change if the value of quote is not known at compile time)

there is an error shows up to be "comparison between pointer and integer ('int' and 'const char *')"

char * piglatin(const char s[], int len) {
char * result[len+3] = s[];
char * current[len+3] = s[];
if(s[0]=="o"||"u"||"e"||"a"||"i"){
result[len-1] = "y";
result[len-2] = "a";
result[len-3] = "-";
}
else{
for(int i = 0; i<len-1; i++){
result[i] = current[i+1];
result[len-1] = "-";
result[len] = current[0];
result[len+1] = "a";
result[len+2] = "y";
}
}
}
I met a problem when I was doing program homework for my computer science class. the professor want us to append "-ay" after the string s if the first letter of s is vowel, otherwise remove the first letter of s and append "-?ay". My error appears at the "if(s[o]=="o"||"u"||"e"||"a"||"i")" and it said "comparison between pointer and integer ('int' and 'const char *')". I feel confused since s is not a pointer and the right hand side is not integer either.
cmon brother ... use 'o' not "o" for all others to and in if statement you have to compare them all to s[0] like this s[0]=='o'||s[0]=='u'||s[0]=='e'||s[0]=='a' and so on . but you will still get errors so dont forget to return a value of pointer :) and (const char s[]) s is constant how will you change it !!!!!! remove const
There are two issues here. The compiler is complaining because s[0] is a char and "o" (and others) are pointers to char arrays (basically). To fix this, replace "o" with 'o'.
There's a bigger issue though: you are only comparing s[0] to 'o'. The other things in your test will all evaluate to true:
if(s[0]=='o'||s[0]=='u'||s[0]=='e'||s[0]=='a'||s[0]=='i'){
In the below, s[0] is a char - so a form of integer, where "o" is a string - const char * - so you are comparing a letter 'a'(or such) to the address of the string `"o".
if(s[0]=="o"||"u"||"e"||"a"||"i"){
You should do:
if(s[0]=='o' ... )
However, the || 'u' doesn't mean what I think you think it means. Since none of the characters (or strings in your code) are zero/NULL, they become true, and your if-statement will always be true.
You need to have a comparison statement:
if(s[0] == 'o'|| s[0] == 'u' ... )

Resources