This question already has answers here:
Strcmp pointer from integer without cast
(4 answers)
Closed 7 years ago.
I'm writing a method that splits a given array into 2 parts. It keeps the first half in the original array and puts the other half into a temporary array using a symbol that marks where the split is. I'm getting erros as follows:
Warning: passing argument 2 of ‘strcmp’ makes pointer from integer without a cast
if(strcmp(input[i], symbol) == 0){
^
In file included from process.c:7:0:
/usr/include/string.h:144:12: note: expected ‘const char *’ but argument is of type ‘char’
extern int strcmp (const char *__s1, const char *__s2)
^
process.c:95:16: warning: assignment makes integer from pointer without a cast
input[i] = NULL;
^
process.c:96:26: warning: comparison between pointer and integer
while(input[i + 1] != NULL){
^
process.c:98:22: warning: assignment makes integer from pointer without a cast
input[i + 1] = NULL;
^
Here is my code:
char *splitCommands(char *input, char symbol){
int i = 0, j = 0;
char *temp;
int symbIndex; // where the symbol was
while(input[i] != NULL){
if(strcmp(input[i], symbol) == 0){
symbIndex = i;
input[i] = NULL;
while(input[i + 1] != NULL){
temp[j] = input[i + 1];
input[i + 1] = NULL;
i++;
j++;
}
break;
}
i++;
}
return temp;
}
You can directly do this comparison
if (input[i] == symbol)
because input[i] and symbol have type char and hence you compare their values, when the are strings you compare addresses which is why you need strcmp().
And
input[i + 1] = NULL;
is equivalent to
input[i + 1] = (void *) 0;
hence, you are trying to assign a pointer, to a char, which is also wrong, perhaps you mean
input[i + 1] = 0;
or in a more c-ish fashion
input[i + 1] = '\0';
Also, the while condition, the same problem, just
while (input[i])
would be enough, if you like your code to be more readable, I personally think that,
while (input[i] != '\0')
is more readable.
And you can't use temp like that because it's uninitialized, you need to allocate space for it, like this
temp = malloc(1 + estimatedSizeInBytes);
if (temp == NULL)
return NULL;
/* add the '\0' terminator */
temp[realSize - 1] = '\0';
where realSize <= estimatedSize.
You should also remember to free() the pointer returned by this function when you finish using it.
input[i] and symbol are char. So campare by imput[i] == symbol. And don't forget to allocate memory for char *tmp
There are several problems with your code but one of the primary problems and reason for your compiler errors is that strcmp() takes two pointers to c style strings as arguments. You are passing two char's to it, instead of pointers.
Another problem is that you're assigning a char to NULL, however NULL should only be used for pointers, not other types like char/int/float. If you're trying to check for the end of a c style string, check if the char is equal to 0 or '\0' instead. You'll probably have to spend more time learning about c style strings and pointers before you can finish this program.
I won't complete your assignment/work for you but I will give you an example of how to use strcmp():
#include <string.h>
#include <stdio.h>
int main()
{
char String1[4] = "abc";
char String2[4] = "xyz";
int Result = strcmp(String1, String2);
if (Result < 0)
printf("%s < %s\n", String1, String2);
if (Result == 0)
printf("%s = %s\n", String1, String2);
if (Result > 0)
printf("%s > %s\n", String1, String2);
return 0;
}
Output: abc < xyz
Here's an additional strcmp() reference from cplusplus.com.
Related
I'm trying to declare an array of char dynamically, what I need to do is adding the newest character to the string which works fine, the problem is that when I try to print it out, at the beginning of the string there are some unknown characters.
char add[2];
char str2[200];
char c;
int temp = -1;
int num = 0;
char *str3;
str3 = malloc( (size_t)count ); //str3 = malloc(sizeof(char)) not working
while((c= getch()) !='\r')
{
for (int i = 0;i<200;i++)
{
if (str2[i] =='\0')
{
num = i;
break;
}
}
//printf("Num: %d\n",num);
if ((temp == -32) || (temp == 0))
{
}
else
{
if(isalnum((char)c) == 0)
{
if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105)|| (c == 32))
{
realloc(str3,sizeof(char)+2);
printf("true: %c\n",c);
//realloc(str2,sizeof(char)+1);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("%s\n",str2);
printf("%s\n",str3);
}
else if (c == 8)
{
printf("Deleting something...\n");
}
}
else
{
realloc(str3,sizeof(char)+2);
printf("true: %c\n",c);
//realloc(str2,sizeof(char)+1);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("%s\n",str2);
printf("%s\n",str3);
}
}
printf("ASCII Code: %d\n",c);
temp = c;
}
To get some memory to your string, you have to tell malloc how many bytes of memory you want. sizeof(char) returns 1, therefore, you'll only have 1 byte. In C, strings are terminated by the NULL byte (\0), and printf and others will print until they find that NULL terminator.
If you do something like this:
char *str = malloc(1);
*str = 'a';
printf("%s", str);
You will probably get a very strange output, since you have no NULL terminator.
When you use the unsigned x; str = malloc(x);, it's actually undefined how many bytes you have, since that x variable is not initialized.
Since your question is very unclear, what I can tell you (from what I think you're asking) is how to actually get space for a string of 63 characters plus the NULL terminating byte.
char *str = malloc(64);
strcpy(str, "Stack Overflow");
printf("%s", str);
That will do it.
Also note that the memory block returned by malloc will not be zeroed, therefore you can't possibly know what's in it (that could be the reason you're getting garbage when you're printing).
I recommend you read about memory allocation in a good C book or in Wikipedia...
After your edit and "MCVE"
I made some edits to what I think it is you want. The modifications are explained in the comments of the source. Let me know if you have any doubts.
#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc, free, realloc */
#include <string.h> /* strcat */
#include <ctype.h> /* isalnum */
#include <conio.h> /* getch */
int main(void)
{
char add[2];
char str2[200];
char c;
int temp = -1;
int num = 0;
char *str3;
/* I just think 'count' is an int, since you didn't put it in the code,
* I also deduced that #count will be used as the length of #str3
*/
int count;
/* Here, count is not initialized, so you MUST initialize it in order
* to call malloc with it! Since it seems you want to add character by
* character using realloc, then we just malloc() 2 bytes - 1 for a
* character and one for the NULL terminator.
*/
count = 2;
str3 = malloc(count);
/* You will be using #strcat to append strings to #str3, so you need
* to put a NULL terminator in it, because strcat will look for that
* NULL byte to find where it should append
*/
*str3 = 0x0;
while((c = getch()) != '\r') {
for (int i = 0;i < 200; i++) {
if (str2[i] =='\0') {
num = i;
break;
}
}
if ((temp == -32) || (temp == 0)) {
/* empty */
} else {
if(isalnum((char)c) == 0)
{
if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105)|| (c == 32))
{
/* this is not the optimal way of using realloc, because
* you should first check for errors, but will do for
* this example.
* You must assign the returned value of realloc to str3.
*
* Also, since #count contains the length
* of #str3, you need to increment it.
*/
str3 = realloc(str3, ++count);
printf("true: %c\n",c);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("str2: %s\n",str2);
printf("str3: %s\n",str3);
} else if (c == 8) {
printf("Deleting something...\n");
}
} else {
/* see notes above on realloc */
str3 = realloc(str3, ++count);
printf("true: %c\n",c);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("str2: %s\n",str2);
printf("str3: %s\n",str3);
}
}
printf("ASCII Code: %d\n",c);
temp = c;
}
return 0;
}
In the first two cases, you are only allocating enough space for a single char. If you attempt to write more than one to that block of memory, you'll write past the end of the memory that was allocated for you. Doing so invokes undefined behavior, which in this case manifests as printing strange characters.
In the third case, you allocate x bytes of memory, however x is uninitialized and has an indeterminate value. Reading an indeterminate value is also undefined behavior. In this case it happens to work because the indeterminate value happens to be a valid value and is large enough to hold the string you want, however you can't depend on that behavior.
You need to allocate a byte for every character that you'll need, plus 1 for the terminating null byte that ends a string in C.
Note that the first allocation, this one
str = malloc(sizeof(char));
is exactly equivalent to1
str = malloc(1);
so you don't have room except for one character which is a problem, because it only represents an empty string.
If you allocate this much space you will very likely access memory out of the allocated space, causing undefined and unpredictable behavior. You need to understand what a string in c is,
A string in c is a sequence of non-null characters followed by a null character, so for a string with N characters you need N + 1 array elements (for ascii this equals bytes)
According to that definition of string if you wanted to store the string "Hello" you would need at least the following code
char *str = malloc(6);
if (str != NULL) {
str[0] = 'H';
str[1] = 'e';
str[2] = 'l';
str[3] = 'l';
str[4] = 'o';
str[5] = '\0'; // Or equivalently str[5] = 0;
}
as you can see, the last character being '\0' or 0 — which is the same — is very important.
All the functions in the standard library of c which expect a string parameter expect that there is the null terminator. For instance strlen() will count characters until it reaches the '\0', if it's not there then you can't predict where it is going to stop counting, this causing undefined behavior.
1sizeof(char) is as defined by the c standard always equal to one.
I'm learning UNIX system programming. I'm writing a simple shell application for UNIX (I'm on OS X Yosemite ver 10.10.5 and I use Xcode). I had some experience with C but not much.
Utility programs work fine and will print unicode characters (though ls prints '????' instead of it in Xcode console, but it seems to be the problem of the debugger itself).
I've made a little research and found out that strcmp() should work fine with it too, as far as it just compares bytes and looks for a zero byte in the end. Reading input should be ok too, as you just read bytes.
I've also read that unicode string shouldn't contain null bytes. However, some input will cause EXC_BAD_ACCESS when doing `strcmp().
Code:
Reading user input:
char* readCommand(void) {
int buffer_size = LINE_BUFFER_SIZE;
char *buffer = malloc(sizeof(char) * buffer_size);
int position = 0;
int character;
if(!buffer)
{
fprintf(stderr, "readCommand failed: memory allocation error");
exit(ALLOCATION_ERROR);
}
while (1) {
character = getchar();
if(character == EOF || character == '\n')
{
buffer[position] = '\0';
char* cmd = buffer;
free(buffer);
return cmd;
}
else {
buffer[position] = character;
}
if(++position >= sizeof(buffer))
{
buffer_size += LINE_BUFFER_SIZE;
buffer = realloc(buffer, sizeof(char) * buffer_size);
if(!buffer) {
fprintf(stderr, "readCommand failed: memory reallocation error");
free(buffer);
exit(ALLOCATION_ERROR);
}
}
}
return NULL;
}
Split args:
int split_string_quotes(char* source, char** argv, size_t arg_count)
{
enum split_states state = DULL;
char* p, *word_start = NULL;
int character;
int argc = 0;
for(p = source; argc < arg_count && *p != '\0'; p++)
{
character = (unsigned char) *p;
switch (state) {
case DULL:
if(isspace(character))
{
continue;
}
if(character == '"')
{
state = IN_STRING;
word_start = p+1;
continue;
}
state = IN_WORD;
word_start = p;
continue;
case IN_WORD:
if(isspace(character))
{
state = DULL;
*p = 0;
argv[argc++] = word_start;
}
continue;
case IN_STRING:
if(character == '"')
{
state = DULL;
*p = 0;
argv[argc++] = word_start;
}
continue;
}
}
if(state != DULL && argc < arg_count)
{
argv[argc++] = word_start;
}
argv[argc] = NULL;
return argc;
}
That's where strcmp is:
int shell_execute(char **args)
{
for(int i = 0; i < 3; i++)
{
if(strcmp(args[0], commands[i]) == 0)
{
return (*standardFuncs[i])(args);
}
}
shell_launch(args);
return 0;
}
And the main loop
char* current_dir = malloc(sizeof(char)*PATH_MAX);
char* args[MAX_ARGS];
char* command;
printf("dolphinShell (c) Alex Kale 2016\n");
while (1)
{
getwd(current_dir);
printf("dsh: %s-> ", current_dir);
command = readCommand();
printf("%s\n", command);
split_string_quotes(command, args, MAX_ARGS);
if(shell_execute(args) == -1) break;
}
free(current_dir);
return 0;
So, the problem is that some unicode strings I type work fine and never cause EXC_BAD_ACCESS, but when I type фывпфвыапы, for example, it breaks. I think the problem is with accessing args[0], but here's the debugger's output:
Printing description of args:
(char **) args = 0x00007fff5fbff900
*args char * 0x101800a00 0x0000000101800a00
Printing description of *(*(args)):
(char) **args = '\xd1'
So it thinks that args[0] is empty, but is it empty? Or is it confused by all the zeroes?
I'm really confused, I've spent a lot of time researching and seem to be stuck here.
I have also tried using wchar_t and wcscmp(), but it doesn't work good with execvp() and doesn't solve the problem.
I have also tried gcc -Wall -Wextra and here's the output:
main.c:53:26: warning: comparison of integers of different signs: 'int' and
'size_t' (aka 'unsigned long') [-Wsign-compare]
for(p = source; argc < arg_count && *p != '\0'; p++)
~~~~ ^ ~~~~~~~~~
main.c:92:30: warning: comparison of integers of different signs: 'int' and
'size_t' (aka 'unsigned long') [-Wsign-compare]
if(state != DULL && argc < arg_count)
~~~~ ^ ~~~~~~~~~
main.c:124:23: warning: comparison of integers of different signs: 'int' and
'unsigned long' [-Wsign-compare]
if(++position >= sizeof(buffer))
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
main.c:180:18: warning: unused parameter 'args' [-Wunused-parameter]
int dHelp(char **args)
^
main.c:203:18: warning: unused parameter 'args' [-Wunused-parameter]
int dExit(char **args)
^
main.c:210:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, const char** argv)
^
main.c:210:33: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, const char** argv)
^
7 warnings generated.
But I don't think that's the case (correct me if I'm wrong).
There are multiple bugs in the shown code.
char* cmd = buffer;
free(buffer);
return cmd;
This returns a pointer to a deleted char buffer. Continuing use of this pointer results in undefined behavior.
if(++position >= sizeof(buffer))
buffer is a char *. This is equivalent to:
if(++position >= sizeof(char *))
Which would be either 4 or 8 bytes, depending on your hardware platform. This needlessly resizes the buffer, every time it grows larger than 4 or 8 bytes.
You seem to believe that sizeof() gives the size of the malloc-ed buffer. It does not.
In conclusion: your overall approach here is to write a big pile of code, and then try to see if it works correctly. This is the wrong way to do it. You need to write one, small function. Such as the one that reads a line into a buffer. Test it. Verify that it works. Now that you know it works, move on and write the next small part of your overall program.
One huge bug in your code is the way you read the input. Look at this part:
if(character == EOF || character == '\n')
{
buffer[position] = '\0';
char* cmd = buffer;
free(buffer);
return cmd;
}
Here you are terminating buffer with nil, as you should. Then you assign cmd to point to the same memory as buffer, free the buffer and return the pointer to the already freed memory. If after this you use the returned pointer for anything it is not allowed and anything can happen. The memory could be reused somewhere, you'd get access violations or maybe a volcano erupts near you.
Assigning a pointer to another variable doesn't make a copy of the memory, it just makes them point at the same place. You cannot free the memory before you stop using the contents. This most likely is causing your issues.
I'm attempting to fill a few strings using a function, but the strings don't seem to be getting filled properly. The print statement is just 4 empty lines. BUT if I un-comment the char ** pls line, it prints all three strings properly even if I never use the variable pls anywhere. It also runs properly in debug mode without the pls variable existing. I'm not entirely sure what I did that it isn't happy about.
char * dataFile = (char *) calloc(64, sizeof(char));
//char ** pls = &dataFile;
char * queryFile = (char *) calloc(64, sizeof(char));
char * outFile = (char *) calloc(64, sizeof(char));
for(i = 1; i <argc; ++i)
{
char command[3];
char * iterator = argv[i];
command[0] = *iterator;
++iterator;
command[1] = *iterator;
++iterator;
command[2] = *iterator;
if(strcmp(command, "df=") == 0)
determineFileString(iterator, &dataFile);
else if(strcmp(command, "if=") == 0)
determineFileString(iterator, &queryFile);
else if(strcmp(command, "of=") == 0)
determineFileString(iterator, &outFile);
}
printf("%s\n%s\n%s\n", dataFile, queryFile, outFile);
void determineFileString(char * iterator, char ** file)
{
char * p = *file;
++iterator;
while(*iterator != '\0')
{
*p = *iterator;
++p;
++iterator;
}
*p = '\0';
}
You are calling strcmp but the first operand does not point to a string. A string is defined as some characters followed by a null terminator.
Your code will also cause undefined behaviour if an argv[i] string is shorter than 2 characters, because you always copy 3 characters out of it.
To fix this, either make command bigger and put a null terminator on the end, or use memcmp instead of strcmp. (But be careful with memcmp as it also causes UB if both objects are not at least as big as the size).
Here is a possible fix:
for(i = 1; i <argc; ++i)
{
if ( strlen(argv[i]) < 3 )
continue;
if ( memcmp(argv[i], "df=", 3) == 0 )
determineFileString(argv[i] + 3, &dataFile);
else if // etc.
}
BTW, the determineFileString function does not do any buffer size checking (it could buffer overflow). I'd suggest redesigning this function; perhaps it could do a length check and call realloc inside the function.
Can someone tell me how to correct this warning/error. I am trying to get just the first character of a string to tell if it a "-".
Error:
grep-lite.c:15:13: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
if(strcmp((char *) pattern[0],"-") == 0)
^
grep-lite.c:29:16: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
while(strcmp((char *) argv[index][0],"-"))
^
Source with warnings/errors:
Line 15:
if (strcmp((char *) pattern[0],"-") == 0)
Line 29:
while (strcmp((char *) argv[index][0],"-"))
Complete Source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "grep-lite.h"
int main(int argc, char * * argv)
{
//initailize variables
int index = 1, lineNumber = 1;
int oneMatchingLine = FALSE;
int invertOpt = FALSE, lineNumOpt = FALSE, quietOpt = FALSE;
char * pattern = argv[argc];
//check if last arguement is invalid by starting with a '-'
if(strcmp((char *) pattern[0],"-") == 0)
{
error(INVALID_PATTERN);
return EXIT_ERROR;
}
//check if they asked for help
if(strcmp(argv[index],"--help") == 0)
{
printHelpStatement();
return EXIT_SUCCESS;
}
//walk through all options
while(strcmp((char *) argv[index][0],"-"))
{
//find and set option
if(processOptions(argv[index], &invertOpt, &lineNumOpt, &quietOpt))
index++;
//if invalid option fai
else
{
error(INVALID_OPTION);
return EXIT_ERROR;
}
}
//walk through stdinput searching for pattern relationship
while(feof(stdin) == 0)
{
//initialize
char * thisLine = NULL;
// get read line with fgets
thisLine = fgets(thisLine, MAX_CHARACTERS, stdin);
//find pattern location in thisLine
char * patternLoc = strstr(thisLine, pattern);
//check if we should print this line based of patternLoc and invertOpt
if((!patternLoc != NULL && !invertOpt) || (pattenLoc == NULL && invertOpt))
{
//see if we should print this line
if(!quietOpt)
printLine(thisLine, lineNumOpt, lineNumber);
}
lineNumber++;
}
I will enumerate the problems I find in your code
The correct usage of strcmp() exists in your code, in this line
if (strcmp(argv[index],"--help") == 0)
strcmp() is intended for string comparison, not character comparison, this
if(strcmp((char *) pattern[0],"-") == 0)
should be
if (pattern[0] == '-')
do not cast the variable to force compilation, instead find the actual cause for the compiler error/warning.
You have a severe error, you don't allocate space for the thisLine char pointer, you must allocate memory via malloc() or just declare it as a char array like
char thisLine[SOME_CONSTANT_NUMBER];
Also, this
while(feof(stdin) == 0)
is never a good idea instead do it like this
char thisLine[100];
while (fgets(thisLine, sizeof(thisLine), stdin) != NULL)
You made another very common mistake, arrays in c are indexed from 0 to N - 1, so
char *pattern = argv[argc]
is wrong, because you are reading one element after the last, the correct code is
char *pattern = argv[argc - 1]
which will give you the last element.
Im trying to remove the first char of the string and keep the remainder, my current code doesnt compile and im confused on how to fix it.
My code:
char * newStr (char * charBuffer)
{
int len = strlen(charBuffer);
int i = 1;
char v;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q'){
for(i=1;i<len;i++)
v = v + charBuffer[i];
}
v = v + '\0';
return v;
}
Gcc: "Warning: return makes pointer from integer without a cast"
Also: "char * newStr (char * charBuffer)" needs to remain the same.
Strings don't work like this in C. You're summing up all of the characters in the buffer into the v variable. You can't use + to concatenate. The code you posted has some serious problems which indicate that there's an understanding gap with how to use C.
Try this:
char *newStr (char *charBuffer) {
int length = strlen(charBuffer);
char *str;
if (length <= 1) {
str = (char *) malloc(1);
str[0] = '\0';
} else {
str = (char *) malloc(length);
strcpy(str, &charBuffer[1]);
}
return str;
}
or this:
char *newStr (char *charBuffer) {
char *str;
if (strlen(charBuffer) == 0)
str = charBuffer;
else
str = charBuffer + 1;
return str;
}
Depending on whether you want to allocate a new string or not. You'll also have to add the code for handling the cases that don't start with 'Q' or 'A'. I didn't include those because I'm not sure exactly what you're trying to do here.
Make sure you do some research into allocating and deallocating memory with malloc and free. These are fundamental functions to be able to use if you're going to be doing C programming.
Well, your description says you want to deal with "strings", but you code deals with char buffers/pointers. The simplest approach to remove the first character for strings would be
const char *newStr(const char *string)
{
return string+1;
}
but as that doesn't look at all like what your code is doing, you probabaly want something different. For example, if you want to just remove a leading 'A' or 'Q' and then copy the string to a buffer, you want something like
char *newStr(const char *string)
{
if (string[0] == 'A' || string[0] == 'Q')
string++;
return strdup(string);
}
You can simply move your char pointer one character in:
char* newstring = oldstring + 1;
Your function is declared to return a char * and you are returning a char.
Furthermore, why don't you just return a pointer to the second character?
char * newStr (char * charBuffer)
{
if (charBuffer && (*charBuffer == 'A' || *charBuffer == 'Q')) return charBuffer + 1;
return charBuffer;
}
Several of the other answers recommended returning charBuffer + 1. As I noted in my previous comment:
This is bad practice. What if the string is dynamically allocated? Perhaps eventually the storage will be freed (starting from the second character). The string should be copied to new storage first.
Freeing a piece of storage from the middle will result in undefined behavior.
Instead, try the strdup function which will return a duplicate of the given string.
#include <string.h>
#include <stdio.h>
char *newStr(char* charBuffer) {
if (charBuffer && (charBuffer[0] == 'A' || charBuffer[0] == 'Q'))
return strdup(charBuffer + 1);
else
return strdup(charBuffer);
}
void main() {
char a[7] = "Advait";
char b[5] = "John";
printf("%s\n",newStr(a)); // Prints "dvait"
printf("%s\n",newStr(b)); // Prints "John"
}