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.
Related
I would like to know what would be the equivalent for filling an array like we do in Python, but in C.
Python example code:
arrayname=[0]*10
randomtextvar="test_text"
for i in range(10):
arrayname[i]=randomtextvar
for k in range(10):
print(arrayname[k]+" "+str(k)+ " position")
I haven't find an solution for this, I don't really understand how to set value to a string (char) array position (in C).
EDIT:
#include <stdio.h>
#include <string.h>
int main() {
int c = 0;
char arr[256];
fgets(arr, 256, stdin);
char spl[] = " ";
char *ptr = strtok(arr, spl);
while (ptr != NULL) {
ptr = strtok(NULL, spl);
// HERE I WANT TO ADD THE ptr value to a new array of strings
c++;
}
return 0;
}
You are doing strtok before the while loop and immediately at the start. So, you are trashing the first token on the line.
kaylum pointed out a simple way to save the strings into a fixed array using strdup.
But, I suspect you'd like something as flexible as what python is doing. So, the array of strings can be dynamically grown as you process many input lines using realloc.
Also, in addition, it's sometimes nice to have the last array element be NULL [just like argv].
Here's some refactored code. I've annotated it to explain what is going on:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
char *ptr;
char *bp;
const char *spl = " \n";
char buf[256];
char **arr = NULL;
size_t arrcnt = 0;
size_t arrmax = 0;
// read in all input lines
while (1) {
// get next input line -- stop on EOF
ptr = fgets(buf,sizeof(buf),stdin);
if (ptr == NULL)
break;
// parse the current line
bp = buf;
while (1) {
// get next token on the current line
ptr = strtok(bp,spl);
bp = NULL;
// stop current line if no more tokens on the line
if (ptr == NULL)
break;
// grow the string array [periodically]
// NOTE: using arrmax cuts down on the number of realloc calls
if (arrcnt >= arrmax) {
arrmax += 100;
arr = realloc(arr,sizeof(*arr) * (arrmax + 1));
if (arr == NULL) {
perror("realloc/grow");
exit(1);
}
}
// add current string token to array
// we _must_ use strdup because when the next line is read any
// token data we had previously would get overwritten
arr[arrcnt++] = strdup(ptr);
// add null terminator just like argv -- optional
arr[arrcnt] = NULL;
}
}
// trim the array to the exact number of elements used
arr = realloc(arr,sizeof(*arr) * (arrcnt + 1));
if (arr == NULL) {
perror("realloc/trim");
exit(1);
}
// print the array
for (char **av = arr; *av != NULL; ++av)
printf("%s\n",*av);
// free the array elements
for (char **av = arr; *av != NULL; ++av)
free(*av);
// free the array
free(arr);
// reset counts and pointer
arrmax = 0;
arrcnt = 0;
arr = NULL;
return 0;
}
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.
/*Input string argument can be up to 3 integer numbers,
separated by spaces. A wild card value, represented by a *
character can replace any one of the integer numbers.*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
void parse(char *data);
int program = 0, version = 0, process = 0;
unsigned char flags = 0;
#define GOT_PROG 0x01
#define GOT_VERS 0x02
#define GOT_PROC 0x04
int main()
{
char data[] = " * 10 7 ";
parse(data);
system("PAUSE");
return 0;
}
void parse(char *data)
{
char *tmp = NULL;
/* advance past whitespace */
while(isspace((int)*data)) data++;
if(*data != '*')
{
program = strtoul(data,&tmp,0);
flags|=GOT_PROG;
printf("%d 11\n",program );
}
if(*tmp == '\0') return;
data=++tmp;
if(*data != '*')
{
version = strtoul(data,&tmp,0);
flags|=GOT_VERS;
printf("%d 22\n",version);
}
else
{
tmp++;
}
if(*tmp == '\0') return;
data=++tmp;
if(*data != '*')
{
process = strtoul(data,&tmp,0);
flags|=GOT_PROC;
printf("%d 33\n",process);
}
}
When my inputs are 3 integers it runs fine.
When my Inputs are two ints and one * it runs fine except when I replace 1st integer with an *, not sure where am I going wrong!! Any suggestions?
Logic error in this block:
char *tmp = NULL;
/* advance past whitespace */
while(isspace((int)*data)) data++;
// If *data == '*', you are skipping the code inside the if block.
// tmp continues to be NULL.
if(*data != '*')
{
program = strtoul(data,&tmp,0);
flags|=GOT_PROG;
printf("%d 11\n",program );
}
// Now you are dereferencing a NULL pointer
// and then setting the value of data to 'NULL + 1'.
if(*tmp == '\0') return;
data=++tmp;
I didn't follow the entire logic of your function but you have to add code that deals with the case of *data == '*'.
Inside your parse(), you're doing
char *tmp = NULL;
then, in case of *data equals *, (Remember, the erroneous case input starts with *) without changing tmp, you're doing
if(*tmp == '\0')
i.e., dereferencing invalid pointer, which in turn invokes undefined behaviour.
You need to take care of the access to tmp in case of the input has a leading *.
FWIW, in the same regards, data=++tmp; is also invalid.
Suggestion: After seeing your logic, I suggest to tokenize the input string using strtok(). That is far better option.
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.