comparing array contents for counter purposes [duplicate] - arrays

This question already has answers here:
How do I properly compare strings in C?
(10 answers)
Closed 3 months ago.
I'm trying to set up a comparison between an array and a given string.
The idea being, that if i started building structures with multiple objects in them, that i could test for a key word in said structure and set up a counter to see how often that element is contained within that structure.
Though this doesnt seem to work, as the terminal output i get is the "ohnoo". Hence I'm thinking that there is something wrong with the comparison in line 8.
The compiler sees nothing wrong with the following code, so its hard to find a solution by myself.
Here's a simple piece of code i tried to test this idea with.
#include <stdio.h>
#include <string.h>
char string1[10] = "Automatic";
int main()
{
if(string1 == "Automatic")
{
printf("huzzah\n");
}
else{
printf("ohnoo\n");
}
}

Strings in C cannot be compared in this way. Rather use strcmp. Otherwise, using == you are determining if they point to the same location in memory, rather than whether their contents are the same.
#include <stdio.h>
#include <string.h>
char string1[10] = "Automatic";
int main()
{
if (strcmp(string1, "Automatic") == 0)
{
printf("huzzah\n");
}
else{
printf("ohnoo\n");
}
}

Related

Why do I get segmentation fault on trying to compare two strings?

I was working on an assignment for a simple assembler that should recognize arbitrary variable names like high programming languages. I tried to use Dynamic allocation to an array of char pointers
I am just trying to make an extensible array of strings and being able to search this array for specific strings But it gives a segmentation fault on the line of trying to compare the two strings [line: 14]
Comp(&buffer[1], Variables[i];
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define Comp(a,b) strcmp(a,b) == 0 ? 1 : 0
char buffer[255], **Variables;
int VariableIndex;
void A_instructionHandler() {
int A_Operand, test = 0;
if (buffer[0]== '#') {
for (int i = 0; i <= VariableIndex; i++) {
test = Comp(&buffer[1], Variables[i]);
if (test) {
A_Operand = i + 16;
break;
}
}
}
}
int main(int argumentCounter, char *arguments[]) {
strcpy(buffer, "#variable");
Variables = (char **)calloc(VariableIndex + 1, sizeof(char**));
A_instructionHandler();
}
Here's that code refactored into something more idiomatic:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void instruction_handler(char* buffer, char** variables) {
switch (buffer[0]) {
case '#':
// This iterates over the NULL terminated array by stopping when
// it hits a NULL pointer, or in other words *v is false.
for (char **v = variables; *v; ++v) {
// If this matches a variable name...
if (!strcmp(*v, &buffer[1])) {
// Variable matched, so show some debugging code
printf("Found variable: %s\n", *v);
return;
}
}
}
}
int main(int argc, char* argv[] ) {
// Create a simple NULL-terminated array of arbitrary size
char *variables[] = {
"variable",
NULL
};
instruction_handler("#variable", variables);
}
Where that variables array can be defined however you like, extended, shrunk, so long as the NULL terminator remains in place at the end.
Some tips based on your original code:
Don't use global variables unless you have an extremely compelling reason. No such reason existed here.
Make your functions clear in intent and purpose.
Pick a naming convention and stick to it.
Use C conventions like strcmp() and just deal with how weird it is, don't wrap that in a #define and invent your own C dialect nobody understands. You'll get used to C over time, it won't bother you as much, and you can code without driving other people on your team up the wall.
Explanations like argc expanded to argumentCounter is better expressed as a comment than an awkwardly long variable name, especially one that's very non-standard. Comments are great. Use them as much as you like!

Why do I get segmentation fault in my code?

I keep getting segmentation fault, how can I fix that. I tryed more variants but I get segmentation fault everytime when I am using if statements. My code is something similar with this:
#include <stdio.h>
#include <string.h>
int main()
{
int i;
char *sentence[300];
fgets(*sentence,300,stdin);
int length=strlen(*sentence);
for(i=0;i<length;i++){
if(sentence[i]=="a")
printf("qwer");
else if(sentence[i]=="b")
printf("asdf");
else if(sentence[i]=="c")
printf("zxcv");
// ...
}
return 0;
}
The first thing you're doing wrong is this:
char *sentence[300];
It looks like you're trying to create a buffer of 300 characters, but what you're really doing is creating an array of 300 character pointers. Change that to:
char sentence[300];
Then you want to change this:
fgets(*sentence,300,stdin);
to
fgets(sentence,sizeof(sentence),stdin);
Then you want to change
int length=strlen(*sentence);
to
int length=strlen(sentence);
You need to have a good understanding of how strings work in C. If you haven't read a good introductory book for C, start there. C is not something you're going to pick up by just reading random pages on the web and StackOverflow.

Getting segmentation fault when indexing a 'mallocced' array

I've been struggling with this one for a few hours now and I'm at a loss as to what's happening. This is the code for program.c:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SPACE 32
#define INITIAL 4
typedef struct {
char *town;
char *country;
} town_t;
typedef struct {
int num_towns, current_size;
town_t **towns_list;
} index_t;
int main(int argc, char *argv[]) {
index_t town_index;
town_index.current_size = INITIAL;
town_index.towns_list = malloc(town_index.current_size * sizeof(*(town_index.towns_list)));
assert(town_index.towns_list != NULL);
printf("Step: %d\n", 1);
town_index.towns_list[0]->town = malloc(4 * sizeof(*(town_index.towns_list[0]->town)));
printf("Step: %d\n", 2);
assert(town_index.towns_list[0]->town != NULL);
return 0;
}
On Linux this is how it runs:
./program
Step: 1
Segmentation fault
but on Windows it prints out
program.exe
Step: 1
Step: 2
as I'd expect, which really isn't helping. For the Linux output, however, clearly the first print statement is being executed but not the second, which would lead me to think that the line between is that one at fault. Particularly, I think doing town_index.towns_list[0] is causing me issues, but I cannot say why.
This is a relatively complex data structure, so maybe I'm getting lost at some point. Basically town_index is meant to be a index struct that contains the current number of towns in towns_list and current_size which reflects the space currently available to save towns. It also contains an array of pointers to town_ts which contain the name and country as strings.
I've tried to use Valgrind, but it's really not helping out much. Here's a Pastebin for those who want to see.
This is a simplified scenario of what I was experiencing in another program, so don't any mind magic numbers and whatnot.
This is on VirtualBox Linux Mint 64-bit.
Unrelated question, if anyone can: How do I get Valgrind to display the precise lines? I see that everywhere else online, but my output just tells me the folder in which the program and function is, which isn't much help.
You initialized town_index.towns_list, but not town_index.towns_list[0], so town_index.towns_list[0]->town is undefined behaviour.
You missed something like
for (int i = 0; i < town_index.current_size; ++i)
town_index.towns_list[i] = malloc(sizeof **town_index.towns_list);
for the second dimension.
town_index.towns_list and town_index.towns_list[0] are not the same. You initialize town_index.towns_list but town_index.towns_list[0] is equal to 0. The crash caused by dereferencing town_index.towns_list[0]

Node v8 variable default NULL but reassign based on argument passed

I'm sure it's really basic but I haven't been able to find anything like it (perhaps I'm going about it completely the wrong way).. I'm trying to pass str to the 'call_to_c_lib_func' function which takes either NULL or a string (char*).
#include <stdio.h>
#include <string.h>
#include <v8.h>
void test(const v8::FunctionCallbackInfo<Value>& args) {
char *str = NULL;
if (!args[3]->IsNull() && !args[3]->IsUndefined()) {
String::Utf8Value arg_str(args[3]->ToString());
str = *arg_str;
}
// Following function takes either NULL or char*
call_to_c_lib_func(str);
}
Edit: Post originally contained simplified C code for this which didn't really help explain the problem, hopefully this clarifies it a bit.
Your post doesn't ask a question or explain what problem you are having with the code. So I am assuming you ran the code exactly as posted and sometimes the call to the function behaves oddly or crashes.
Your existing code fails because:
String::Utf8Value arg_str(args[3]->ToString());
is inside a { code block } but you try to access its contents after that code block has exited (and therefore after arg_str has been destroyed).
Instead you could write:
String::Utf8Value temp;
char *str = NULL;
if (!args[3]->IsNull() && !args[3]->IsUndefined())
{
temp = args[3]->ToString();
str = *temp;
}
call_to_c_lib_func( str );
Of course there are many ways to skin a cat, just watch out when using v8::String that you do not use the result of operator* after the string has been destroyed, because it returns a pointer to the content of the string.
NB. I'm not familiar with V8 so there may be a more elegant way of accessing args[3]'s string data that neither of us is aware of.

concatenate variable onto another variable

const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
I can't figure out why I'm getting an error of:
error: expected ‘)’ before string constant
Basically I just want to concatenate the variable SITE_NAME onto SITE_ROOT. The error is on the sprintf line. Any ideas?
UPDATE: So the code works if it is inside main(). I had it outside of main() so that I could use those variables inside of functions.
The error looks like it might not be shown in the code but the sprintf should be:
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
EDIT:
Here is my complete test code if that helps at all:
#include <string.h>
#include <stdio.h>
int main()
{
const char *SITE_NAME = "test";
char SITE_ROOT[19];
sprintf (SITE_ROOT, "/var/www/html/%s", SITE_NAME);
printf( "%s\n", SITE_ROOT ) ;
return 0 ;
}
As has been pointed out, the direct problem is that you're trying to call sprintf from outside a function.
You mentioned that you are setting the strings this way because you're using SITE_NAME by itself in addition to concatenating it with the path and you want to only have to change it in one place. This is a good goal, known in some circles as "don't repeat yourself" (often abbreviated DRY). However, even if the code worked (say, because you moved the sprintf call into main), you haven't really achieved your goal due to the following line:
char SITE_ROOT[19];
You are declaring a fixed length array exactly big enough to hold "/var/www/html/test", which is just asking for a buffer overflow. When you change SITE_NAME from "test" to, for example, "someRealSiteName", you'll very probably overwrite something else when you concatenate, causing unpredictable results. So you have to manually recalculate the length of the final string and update the array size (which would be easy to get wrong, say by forgetting to add 1 for the null terminator) every time you change SITE_NAME.
You could, of course, limit the length of SITE_NAME and size SITE_ROOT to hold the longest possible path, but it'd be an artificial limit and you might end up wasting space. Furthermore, you'd still have to verify the length isn't exceeded at run-time (or use a function that will ignore extra characters).
Instead, you could dynamically set the size of SITE_ROOT like so:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const char SITE_PATH[] = "/var/www/html/";
const char SITE_NAME[] = "someRealSiteName";
char *SITE_ROOT = NULL; // just making this explicit, would be set to 0 anyway
int main(void)
{
size_t siteRootLength = strlen(SITE_PATH) + strlen(SITE_NAME);
SITE_ROOT = malloc(siteRootLength + 1); //don't forget to account for the terminating '\0'
strcpy(SITE_ROOT, SITE_PATH);
strcat(SITE_ROOT, SITE_NAME);
printf("%s\n", SITE_NAME):
printf("%s\n", SITE_PATH):
printf("%s\n", SITE_ROOT):
return 0;
}
This solution is okay, but has some drawbacks:
SITE_ROOT can't be a const pointer , so both the string and the pointer itself could be accidentally changed
Site path and name will each be in memory twice (though it sounds like you're okay with that)
Concatenation is being done at run-time when it could be done at compile-time
Code is longer and more complex than necessary for such a simple task
Risk that SITE_ROOT is used before it has the correct value (or is even a valid pointer/string!) in some other initialization code or another thread.
I feel something like the following is better:
#include <stdio.h>
#define SITE_PATH_MACRO "/var/www/html/"
#define SITE_NAME_MACRO "someRealSiteName"
// the preprocessor will merge the two string literals into one
#define SITE_ROOT_MACRO SITE_PATH_MACRO SITE_NAME_MACRO
// you could do without some or all of these if you don't need them
// (or are willing to use the macros directly)
const char SITE_PATH[] = SITE_PATH_MACRO;
const char SITE_NAME[] = SITE_NAME_MACRO;
const char SITE_ROOT[] = SITE_ROOT_MACRO;
int main(void)
{
printf("%s\n", SITE_NAME);
printf("%s\n", SITE_PATH);
printf("%s\n", SITE_ROOT);
return 0;
}
Since this is a pretty straightforward case, you can simply initialize the string and then concatenate onto it. You might want to add checks to ensure you don't go beyond you string's boundaries though.
strcpy(SITE_ROOT, "/var/www/html/");
strcat(SITE_ROOT, SITE_NAME);

Resources