strcmp failing to compare strings properly - c

I'm having trouble using strcmp in C.
I'm trying to compare a program's arguments using strcmp but even though the strings are the same it doesn't work. Here is the portion of code.
while(strcmp(argv[i], "-e") != 0)
So for i = 11 if I print the value of argv[i] I get
printf("String %s i %d", argv[i],i);
>> String -e i 11
But the while keeps on going. Any ideas why this is happening?
Code:
while(strcmp(argv[i], "-e") != 0 || i != argc)
{
printf("String %s i %d", argv[i],i);
if(!isdigit((unsigned char)*argv[i]) && strcmp(argv[i], "-t") != 0)
{
archivo = fopen(argv[i] , "r");
TOT_IMG = TOT_IMG + 1;
for(t=0;t<NUM_FUNC_TRAZO;t++)
{
for(d=0;d<NUM_FUNC_DIAMETRICA;d++)
{
for(c=0;c<NUM_FUNC_CIRCO;c++)
{
if (fscanf(archivo, "%s",el) != EOF)
{
par->vector_circo[t][d][c] = strtod(el,NULL);
par->clase = clase;
}
else
{
break;
}
}
}
}
par_temp = par;
par->siguiente = (parametros_lista) malloc(sizeof(parametros_elem));
par = par->siguiente;
par->anterior = par_temp;
}
else
{
if(strcmp(argv[i], "-t") != 0)
{
clase = atoi(argv[i]);
CLASES = CLASES + 1;
}
}
i = i + 1;
}

Let's look at this:
while(strcmp(argv[i], "-e") != 0 || i != argc)
OK, so let's assume strcmp correctly returns 0 when argv[i] is "e". We'll assume this because it's exceedingly unlikely that there's a bug in your library implementation of strcmp.
What happens if strcmp returns 0? Well, things don't just stop, your code checks whether i != argc is true. Is it? My psychic debugging skills tell me that you should look into that second part of the while.
You may also want to note that it's possible that your code could, potentially, access argv[argc], which is NULL. You may get lucky if strcmp is lenient when the input is NULL, but it's a bug that you should fix.

I'd rather recommend you to use getopt (3). This is widely used approach to parameters parsing conforming with POSIX.
Also there was another question related to achieving getopt.h interface on windows: getopt.h: Compiling UNIX C-Code in Windows. What's important it is answered (Xgetopt) so portability should be not a case.

Related

c- sysmalloc assertion problems

I am hoping that someone can help me understand where I have gone wrong here. I am implementing a program to check for spelling correctness. In the process I use a trie data structure to load into memory a dictionary text file to check words against.
Overall it seems to operate as expected but I get a lot of problems when loading in the longest possible word, namely pneumonoultramicroscopicsilicovolcanoconiosis. I do not understand why but first let me present some code -
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
fprintf(stderr, "Could not open %s dictionary file.\n", dictionary);
return false;
}
// Initialise the root t_node
root = (t_node *) malloc(sizeof(t_node));
if (root == NULL)
{
fprintf(stderr, "Could not allocate memory to trie structure.\n");
return false;
}
// Set all current values in root to NULL and is_word to false
for (int i = 0; i < ALPHA_SIZE; i++)
{
root->branch[i] = NULL;
}
root->is_word = false;
while (1)
{
// Create char aray to hold words from .txt dictionary file once read
char *word = (char *) malloc((LENGTH + 1) * sizeof(char));
if (fscanf(dict, "%s", word) == EOF)
{
free(word);
break;
}
t_node *cursor = root;
int len = strlen(word) + 1;
for (int i = 0; i < len; i++)
{
if (word[i] == '\0')
{
cursor->is_word = true;
cursor = root;
word_count++;
}
else
{
int index = (word[i] == '\'') ? ALPHA_SIZE - 1 : tolower(word[i]) - 'a';
if (cursor->branch[index] == NULL)
{
cursor->branch[index] = (t_node *) malloc(sizeof(t_node));
for (int j = 0; j < ALPHA_SIZE; j++)
{
cursor->branch[index]->branch[i] = NULL;
}
cursor->branch[index]->is_word = false;
}
cursor = cursor->branch[index];
}
}
free(word);
}
fclose(dict);
return true;
}
This is my entire function to load in a dictionary into memory. For reference I defined the trie structure and created root prior to this function. LENGTH is defined as 45 to account for the longest possible word. And ALPHA_SIZE is 27 to include lower case letters plus apostrophes.
As I said already with all other shorter words this function works well. But with the longest word the function works through about half of the word, getting up to index 29 of the word variable before suffering a sysmalloc assertion issue where it then aborts.
I've tried to find what is happening here but the most I can see is that it suffers the fault at -
cursor->branch[index] = (t_node *) malloc(sizeof(t_node));
once it gets to the 29th index of word, but no other indexes prior. And all other posts I can find relate to functions giving this error that do not work at all rather than most of the time with an exception.
Can anyone see what I cannot and what may be the error I made in this code? I'd appreciate any help and thank you all for your time taken to consider my problem.
* UPDATE *
First of all I want to thank everyone for all of their help. I was so pleasantly surprised to see how many people responded to my issue and how quickly they did! I cannot express my gratitude to all of you for your help. Especially Basile Starynkevitch who gave me a great amount of information and offered a lot of help.
I am extremely embarrassed to say that I have found my issue and it's something that I should have caught a LONG time before turning to SO. So I must apologise for using up everyone's time on something so silly. My problem lied here -
else
{
int index = (word[i] == '\'') ? ALPHA_SIZE - 1 : tolower(word[i]) - 'a';
if (cursor->branch[index] == NULL)
{
cursor->branch[index] = (t_node *) malloc(sizeof(t_node));
for (int j = 0; j < ALPHA_SIZE; j++)
{
cursor->branch[index]->branch[j] = NULL; // <<< PROBLEM WAS HERE
}
cursor->branch[index]->is_word = false;
}
cursor = cursor->branch[index];
}
In my code originally I had 'cursor->branch[index]->branch[i] = NULL' where I was iterating through 'int j' in that loop, not i ....
Sooooo once again thank you all for your help! I am sorry for my poorly formatted question and I will do better to abide by the SO guidelines in the future.
Your
char *word = (char *) malloc((LENGTH + 1) * sizeof(char));
is not followed by a test on failure of malloc; you need to add:
if (!word) { perror("malloc word"); exit(EXIT_FAILURE); }
before
if (fscanf(dict, "%s", word) == EOF)
since using fscanf with %s on a NULL pointer is wrong (undefined behavior, probably).
BTW, recent versions of fscanf (or with dynamic memory TR) accepts the %ms specifier to allocate a string when reading it. On those systems you could:
char*word = NULL;
if (fscanf(dict, "%ms", &word) == EOF))
break;
and some systems have getline, see this.
At last, compile with all warnings and debug info (gcc -Wall -Wextra -g with GCC), improve your code to get no warnings, and use the debugger gdb and valgrind.
BTW pneumonoultramicroscopicsilicovolcanoconiosis has 45 letters. You need one additional byte for the terminating NUL (otherwise you have a buffer overflow). So your LENGTH should be at least 46 (and I recommend choosing something slightly bigger, perhaps 64; in fact I recommend using systematically C dynamic memory allocation and avoiding hard-coding such limits and code in a more robust style, following the GNU coding standards).

C strstr not working correctly

I am trying to use strstr to search for any matches using a substring and comparing it to a line of text but haven't been successful in getting a match so far. I am opening and reading a file using popen while trying to do a search with only the ipv4 address looking for matches. What is wrong with my code? Any help will be much appreciated, thanks.
char *buffe = malloc(sizeof(char));
FILE *rib_file = popen("bgpdump -Mv rib.20160101.0000.bz2", "r");
while(fgets(buffe, sizeof(buffe), rib_file)!=NULL) {
if(buffe[strlen(buffe)-1] == '\n')
buffe[strlen(buffe)-1] = '\0';
for (int i = 0; i < argc; i++) {
if((strstr(buffe, argv[i])) != NULL) {
printf("A match found on line: %d\n", line_num);
printf("\n%s\n", buffe);
find_result++;
}
line_num++;
}
}
if(find_result == 0) {
printf("\nSorry, couldn't find a match.\n");
}
if (rib_file) {
pclose(rib_file);
}
free(buffe);
}
an example of what buffe is like:
TABLE_DUMP2|01/01/16 00:00:38|B|202.232.0.3|2497|223.255.254.0/24|2497 7473 3758 55415|IGP
I am trying to print the exact line as above when my code finds a match.
The sizeof function tells you the size of a type. Since buffe is a pointer, your call to sizeof(buffe) will get you the size of a pointer on your platform which is almost certainly not what you want. Did you mean to pass fgets the size of the thing buffe points to?

C - scanf waits until all parts in format can be evaluated

I don't have a lot of time, and a lot of the stuff about stdin just raises a lot more questions than it answers at this stage. I was hoping to test for multiple types of commands passed with mutliple instances of scanf.
If I do this:
char inputChar;
char inputChars[15] = { NULL };
int inputInt;
double inputDec;
if(scanf("%c %d %lf",&inputChar,&inputInt,&inputDec) == 3) {
...
}
else if(scanf("%c %d %s",&inputChar,&inputInt,&inputChars) == 3) {
...
}
else if(scanf("%c %d",&inputChar,&inputInt) == 2) {
...
}
else if(scanf("%c",&inputChar) == 1) {
...
}
else {
...
}
And then type a single character and hit Enter, the console waits until I enter another value before assessing whether or not there's a match.
Update
This seems to work fine, except that it expects your input to the perfect whenever it's used. If a user types aa then changes it to a 10 before hitting Enter, it matches the 4th evaluation. It's wrong for two reasons:
Because it should match the 3rd if it's capturing input correctly; and
Because if it doesn't, aa should be filtered into the 5th evaluation.
Revised code:
char input[50] = { NULL };
char inputChar = NULL;
char inputChars[15] = { NULL };
int inputInt;
double inputDec;
printf("Input String:\n>");
fgets(input,sizeof(input),stdin);
if(sscanf(input,"%c%d %lf",&inputChar,&inputInt,&inputDec) == 3) { }
else if(sscanf(input,"%c%d%s",&inputChar,&inputInt,&inputChars) == 3) { }
else if(sscanf(input,"%c%d",&inputChar,&inputInt) == 2) { }
else if(sscanf(input,"%c",&inputChar) == 1) { }
else { }
Doing something like this shows that backspace is not being filtered out:
for(int i=0;i<50;i++) {
if(input[i] == (char) 10) { break; }
printf("\n%c %d",(char) input[i],(int) input[i]);
}
So it appears fgets is out of the picture.
The statements are executed in order. So it's the first scanf call that waits for more input. If the input doesn't match the first call, then the next scanf call will start all over, waiting for input. And so on.
Instead you should use fgets to read the whole line, and then use sscanf on the line.
Please explain what "clears the input buffer" means. Do you mean _flushall erases my keystrokes before they occur? How could it do this? Perhaps you mean that you've already read the data that you need from the line, and you don't care about the rest of the line. In that case, I assume you wish to "read and discard all characters up to and including the next newline". I have a portable mechanism to do that:
for (int c = getchar(); c >= 0 && c != '\n'; c = getchar());
You may also wish to read this related answer.
edit: It has just occured to me that the behaviour you desire might be expressed as follows:
char inputChar;
char inputChars[15] = { NULL };
int inputInt;
double inputDec;
int x = scanf("%c%d", &inputChar, &inputInt);
if (x == 2 && scanf("%lf",&inputDec) == 1) {
...
}
else if (x == 2 && scanf("%14s", inputChars) == 1) {
...
}
else {
...
}
Probably not the best way to go about it but it works.
Using the iostream library run getline(std::cin,input); to capture input to std::string input then use sscanf however many times on input.c_str().

argc argv problems

Can someone please tell me why this code will not work? It does compile. When I type decrypt as the argv[1] argument in the command line, it still gives me the else output. i.e. argv[1] is not satisfied even though it should be. This is a work in progress so ignore the other code
if ((argv[1] == "decrypt"))
{
printf("Decrypting...\n");
c = getc(fp1);
if (c != EOF)
{
fread(inputbuffer, sizeof(char), 50 , fp1);
printf("%s", inputbuffer);
/*while(inputbuffer[i]!=EOF)
{
fputc((inputbuffer[i] / 2) - 5, fp2);
}*/
}
}
else {printf("argv not working");}
You need to use strcmp() to compare strings:
if ((strcmp(argv[1], "decrypt") == 0)
More detail:
What you are comparing are the two memory addresses for the different strings, which are stored in different locations. Doing so essentially looks like this:
if(0x00403064 == 0x002D316A) // Two memory locations
{
printf("Yes, equal");
}

How do I cover unintuitive code blocks?

For some reason, I'm having a hard time trying to cover the block of code below. This code is an excerpt from the UNIX uniq command. I'm trying to write test cases to cover all blocks, but can't seem to reach this block:
if (nfiles == 2)
{
// Generic error routine
}
In context:
int main (int argc, char **argv)
{
int optc = 0;
bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
int nfiles = 0;
char const *file[2];
file[0] = file[1] = "-";
program_name = argv[0];
skip_chars = 0;
skip_fields = 0;
check_chars = SIZE_MAX;
for (;;)
{
/* Parse an operand with leading "+" as a file after "--" was
seen; or if pedantic and a file was seen; or if not
obsolete. */
if (optc == -1 || (posixly_correct && nfiles != 0) || ((optc = getopt_long (argc, argv, "-0123456789Dcdf:is:uw:", longopts, NULL)) == -1))
{
if (optind == argc)
break;
if (nfiles == 2)
{
// Handle errors
}
file[nfiles++] = argv[optind++];
}
else switch (optc)
{
case 1:
{
unsigned long int size;
if (optarg[0] == '+' && posix2_version () < 200112 && xstrtoul (optarg, NULL, 10, &size, "") == LONGINT_OK && size <= SIZE_MAX)
skip_chars = size;
else if (nfiles == 2)
{
// Handle error
}
else
file[nfiles++] = optarg;
}
break;
}
}
}
Any help would be greatly appreciated. Thanks.
It appears this could be reached when more than 2 files are supplied on the command line. In that case, nfiles would reach the value 2 after the name of the second file has been stored in file[1]. When the code checking nfiles == 2 is reached a third time, then the value will already be 2, and the error handling will execute.
There are two if statements in question. That in switch case "1" can only be reached by using the option in longopts with val == 1.
I just thought I would mention in passing that the automatic generation of test cases to satisfy coverage criteria is transitioning from being a research topic to useful applications. One prototype that I know of is PathCrawler.
The difficulties in the source code that may prevent this or a similar tool to work as hoped are the usual suspects: aliasing and dynamic memory allocation.

Resources