I have a linked list and I need to count only some of records according some criteria. I have got this code.
int count_records() {
int number = 0;
RECORD *re;
char criteria[20];
for (re = first; re != NULL; re = re->next) {
criteria = (re->criteria);
if(criteria=="something")
number++;
}
return number; }
Structure of linked list is this:
typedef struct record {
char criteria[20];
struct record *next;
} RECORD;
Problem is that it gives me this error on line criteria = (re->criteria); Error: Invalid array assignment
Any ideas?
Thanks.
You have arrays of char´s. To copy or compare an array, you´ll need to copy/compare each element separately instead of using = and == on the whole array in one go.
And instead of making a loop, you can use strcpy and strcmp in this case:
strcpy(criteria, re->criteria);
if(!strcmp(criteria, "something"))
By the way, this is more C than C++. If you want a C++-like solution, see std::string (then you can work with = and == too)
Indeed, you can't copy arrays using =. Neither can you compare them using ==. They are quite strange, unfriendly things, which need a certain amount of care to use.
If you want to use arrays, you can use the C library to compare them:
if (std::strcmp(re->criteria, "something") == 0)
Since this is C++, you might prefer to use std::string to represent strings; then it's just
if (re->criteria == "something")
and you can copy it with = if you need to (although you don't need to here).
In C++ you can and should use std::string for handling strings. You can find the reference (here).
Just define criteria as std::string criteria; instead of char criteria[20];.
Don't forget to add #include <string> to the include section.
You need to use memcpy in order to copy arrays, but be careful using memcpy when exposed on a public interface. I think there was a recent security issue involving this...
I think that you may wish to pass in the criterion to your count_records() function. I'd render it like this:
int count_records(RECORD *first, const char *criterion) {
int count = 0;
RECORD *re;
for (re = first; re != NULL; re = re->next) {
/* add to count if the strings match */
if(!strcmp(criterion, re->criteria))
count++;
}
return count;
}
Note that it also doesn't rely on first being a global variable which makes the code more reliable and easier to understand.
If you want to copy a char array into another, you need to use strcpy. For example:
// will copy from array1 to array2
strcpy(array2, array1);
You can't directly do array1 = array2. Because in this case you would manipulate the adresses (char *) of the arrays and not their values.
In addition, in order to compare a char array to another, use strcmp instead:
if(strcmp(criteria, "something") == 0)
P.S.: Since you're using C++, std::string is your friend, which you can do assignment using = and comparison using ==.
Dealing with strings in C is a royal pain when you are starting out with the language. You can checkout an online tutorial to get you started.
In the mean time, you can change your code to:
for (re = first; re != NULL; re = re->next) {
if (strcmp(re->criteria, "something) == 0)
number++;
}
You don't need to copy re->criteria to a local variable.
Related
#include <stdio.h>
typedef struct Name {
char Name[10];
}Name;
A(Name a) {
Name NameList[16] = {"", "Holly", "Zia", "Brandon","Jerry","Tom","Katie","Klein","Sophie","Brian","Mary","Ben","Annie","Percy","Zoe","Zack"};
for (int i = 0; i <= 15; i++) {
if (a = NameList[i]) {
for (int k = i; k <= 15; k++) {
printf(NameList + k);
}
break;
}
else {
continue;
}
}
}
I'm getting problems with if (a = NameList[i]) this part.. compiler tells me that I need pointers, but I'm not sure where I have to put them.. help?
a = NameList[i] is an assignment, not comparison. In general you need to use == for comparison.
In C a string is an array of chars, zero terminated. In order to compare strings in C you need to use strcmp. Note that it returns 0 if the strings are equal.
a is not actually a string, but contains one. a.Name is a string. Same applies to NameList[i].
A struct should not contain a member with the same name as the struct itself (even if your compiler accepts it, it is error-prone). You should rename the member Name (e.g. to data).
Therefore after modifying the struct definition, you should change your if to:
if (strcmp(a.data, NameList[i].data) == 0)
First of all the statement if (a = NameList[i]) {bla..} does not do what you think it does. It first executes the command a = NameList[i] and then evaluates if (a != 0) in which case the commands inside the if statement will be executed.
That's a mistake everyone has made at some point ,even more experienced programmers might make this mistake from time to time.
Now I see you are trying to compare two strings ,in C we do this using the function strcmp(a ,b) .If strcmp returns 0 ,the two strings you gave it are equal.
Another mistake you made ,is that you are comparing two structs instead of their contents. You have to use if(!strcmp(a.Name ,NameList[i].Name)) instead.
So your main issue is that you are comparing structs not their contents.
I basically want to store a array of student names, based on a given number. For example, if the user wants to insert 5 names, then the array size will be 5. If the user wants to insert 10 names, then the array size will be 10.
I have a method like this to set a name to a specific element in an array.
void setNames(char *names){
strcpy(name[i], names);
}
Thing is, how do I do array bound checks? I heard that you can only add when the index is -1.
Arrays don't maintain their own size, you have to do that for them. This is part of the reason why vectors are so much easier to deal with, and why everyone will say "wtf, raw arrays? use a vector". An array is just a contiguous chunk of memory, thats it. a vector contains an array, and lets you use it like an array to some extent, but it handles a lot of the housekeeping details for you.
Anyway, if you really want to use a raw array, then you'll need to pass around size information along with it. C strings are a null-terminated array -- just a plain old array, but the last element is \0. This way you can read from it without knowing it's size ahead of time, just don't read past the null character at the end (dragons be there).
EDIT (as the OP indicated he actually wants C):
C answer
What you can do is either create a char array:
char [N][name_length]
where N - number "user wants" (I assume the user will somehow input it into your program), name_length - maximum length the name can have (a C-string, i.e. null-terminated string).
or create an array of your own structs (each holding a separate name and maybe some other information).
C++ answer
A typical way to do this in C++ is by using std::vector<std::string> (assuming you only want to store names, as std::string).
You then add new elements using using push_back() function. And, as vector is implemented as a dynamic array in C++, you won't have to do bound checking.
C code needs to keep track of the array size in another variable.
typedef struct {
char **name;
size_t n;
} Names_T;
void Names_Set(Names_T *names, size_t index, const char *name) {
// See if it is a special value and then append to the array
if (index == (size_t) -1) {
index = names->n;
}
if (index >= names->n) {
size_t newsize = index + 1;
// OOM error handling omitted
names->name = realloc(names->name, newsize * sizeof *names->name);
while (names->n < newsize) {
names->name[names->n++] = NULL;
}
}
char *oldname = names->name[index];
names->name[index] = strdup(name);
free(oldname);
}
void Names_Delete(Names_T *names) {
while (names->n > 0) {
names->n--;
free(&names->name[names->n]);
names->name[names->n] = NULL;
}
free(names->name);
names->name = NULL;
}
int main(void) {
Names_T names = { NULL, 0 };
Names_Set(&names, 3, "Sam"); // set array element 3
Names_Set(&names, (size_t) -1, "Thers"); // Append to array
Names_Delete(&names);
return 0;
}
When programming in C/C++ (unless using C++11 or newer), you will manipulate arrays as pointers. That means you won't know the size of an array unless you save it. What char str[10] really means is str's address + 10 * sizeof(char). You are directly dealing with memory here.
If you want a high level approach for that, take a look at C++11. std::array and std::vector are there for you. From the documentation, look how std::array is defined:
template <
class T,
std::size_t N
> struct array;
It means it stores its own size and has useful functions as well, such as size(), at(), back() etc.
For example, I have this block:
int nFirst, nSecond;
char sInput[10];
printf("Which variable to change to 10?");
scanf("%s", &sInput);
// BAD - inflexible and unmaintainable
if(strcmp(sInput,"nFirst") ==0){
nFirst = 10;
}
else if (strcmp(sInput,"nSecond")==0) {
nSecond =10;
}
Is there a nice way to do this? like treat a string as if its a variable name?
No, there is no "nice" way of doing this in C. Variable names (typically) aren't preserved in the generated machine code, except to support debugging. C doesn't have a built-in mechanism for translating a string value into a reference to a variable of the same name.
You would have to map variable names to variables manually. You could build a lookup table, associating a string value with the address of the corresponding variable:
struct vn {
char *varname;
void *addr;
Typeinfo t;
};
where Typeinfo is some enumeration or other mechanism for encoding the type of the variable, giving you something to the effect of
int foo;
double bar;
char *blurga;
struct vn varsByName[] = { {"foo", &foo, IntType},
{"bar", &bar, DoubleType},
{"blurga", blurga, CharPtrType} };
I don't recommend doing this.
Another, platform-dependent approach is to put all your variables into a shared library and then have access to them by names. Have a look at dlsym/dlopen functions.
void* handle = dlopen("mysymbols.so", RTLD_LOCAL | RTLD_LAZY);
int* var = (int*) dlsym(handle, user_typed_name);
*var = 10; /* modify the variable */
You could implement something like a dictionary or a two-dimensional array which contains the "variable name" and the value. Then this comes down to setting an array element to a new value.
Other than that: C# and other object oriented languages would allow this through reflection, but as C itself isn't object oriented, you can not do that (C++ support for this seems to be very limited).
You can do it with a macro:
#define MAYBESET(name) if (strcmp(sInput, #name) ==0 ){ name = 10; }
#name is the real value of name changed to a string literal.
For a small number of variables then your algorithm should perform well. If there are many variables that could be changed, rather than just two, then another algorithm should be considered. Making this pretty and clear isn't exactly easy in C.
If you really wanted this to be faster you could either do a hash table or use a switch/case like:
int First, Second; // Note that I got rid of your leading n
char sInput[10];
printf("Which variable to change to 10?");
scanf("%s", &sInput);
// BAD - inflexible and unmaintainable
// referring to character array overflow potential, I assume
switch (sInput[0])
{
case 'F':
if (0 == strcmp("irst", sInput+1) )
{
First = 10;
} else
{
// error
}
break;
case 'S':
if (0 == strcmp("econd", sInput+1) )
{
Second = 10;
} else
{
// error
}
break;
default:
// error
break;
}
If you don't like the way that this looks then you could use macros (#define) to make it less big looking, but it would turn out the same. Another option that you could employ would be to write a small program that output the source code of this program which would handle all of the repetitive and tedious parts.
Another way to do this, if all of the variables are of the same type, would be to create an array of them and input their index in rather than a name, but then you have to add code to check against inputting an index out of range of the size of the array.
I'm trying to split a char* to an array of char* in C.
I'm used to program in Java / PHP OO. I know several easy way to do that in these languages but in C... I'm totally lost. I often have segfault for hours x)
I'm using TinyXML and getting info from XML File.
Here's the struct where we find the array.
const int MAX_GATES = 64;
typedef struct {
char *name;
char *firstname;
char *date;
char *id;
char *gates[MAX_GATES];
} UserInfos;
And here's where I fill this struct :
UserInfos * infos = (UserInfos*)malloc(1024);
infos->firstname = (char*)malloc(256);
infos->name = (char*)malloc(128);
infos->id = (char*)malloc(128);
infos->date = (char*)malloc(128);
sprintf(infos->firstname, "%s", card->FirstChild("firstname")->FirstChild()->Value());
sprintf(infos->name, "%s", card->FirstChild("name")->FirstChild()->Value());
sprintf(infos->date, "%s", card->FirstChild("date")->FirstChild()->Value());
sprintf(infos->id, "%s", card->FirstChild("filename")->FirstChild()->Value());
////////////////////////
// Gates
char * gates = (char*) card->FirstChild("gates")->FirstChild()->Value();
//////////////////////////
The only problem is on 'gates'.
The input form XML looks like "gate1/gate2/gate3" or just blank sometimes.
I want gate1 to be in infos->gates[0] ; etc.
I want to be able to list the gates array afterwards..
I always have a segfault when I try.
Btw, I don't really now how to initialize this array of pointers. I always initialize all gates[i] to NULL but It seems that I've a segfault when I do
for(int i=0;i
Thanks for all.
It's OK when I've only pointers but when String(char*) / Arrays / Pointers are mixed.. I can't manage =P
I saw too that we can use something like
int *myArray = calloc(NbOfRows, NbOfRows*sizeof(int));
Why should we declare an array like that.. ? x)
Thanks!
The problem that people frequently have with XML is that they assume all the elements are available. That's not always safe. Thus this statement:
sprintf(infos->firstname, "%s", card->FirstChild("firstname")->FirstChild()->Value());
Isn't safe to do because you don't actually know if all of those
functions actually return valid objects. You really need something
like the following (which is not optimized for speed, as I don't
know the tinyXML structure name being returned at each point and thus
am not storing the results once and am rather calling each function
multiple times:
if (card->FirstChild("firstname") &&
card->FirstChild("firstname")->FirstChild()) {
sprintf(infos->firstname, "%s", card->FirstChild("firstname")->FirstChild()->Value());
}
And then, to protect against buffer overflows from the data you should
really be doing:
if (card->FirstChild("firstname") &&
card->FirstChild("firstname")->FirstChild()) {
infos->firstname[sizeof(infos->firstname)-1] = '\0';
snprintf(infos->firstname, sizeof(infos->firstname)-1, "%s", card->FirstChild("firstname")->FirstChild()->Value());
}
Don't you just love error handling?
As to your other question:
I saw too that we can use something like int *myArray =
calloc(NbOfRows, NbOfRows*sizeof(int)); Why should we declare an array
like that.. ? x)
calloc first initializes the resulting memory to 0, unlike malloc.
If you see above where I set the end of the buffer to '\0' (which is
actually 0), that's because malloc returns a buffer with potentially
random (non-zero) data in it. calloc will first set the entire buffer
to all 0s first, which can be generally safer.
I'm new to programing and was given a task of making a function that puts one array into the other with the following criteria: a variable in the destination array will repeat only once and the source and destination array will be of the same size.
the function i came up with is:
int RemoveDup (int src[],int dst[])
//recive two array compare them and copy the src array to dst,and only the none reacuring
//numbers,the arrays must be from the same size
{
int size_src;
int size_dst;
int i,n=0;
size_src = sizeof(src)/sizeof(int);//determine the size of source array
size_dst = sizeof(dst)/sizeof(int);//determine the size of destination array
if (size_src = size_dst);//checks that the array are in the same size
{
for(i = 0;i < size_src;i++)//the loop for advancing the copying process
{
dst[i] = src[i];
}
while (i<size_dst)
{
dst[i] = dst[i++];
if (dst[i] = dst[i++])//relay on the fact that if the function will find a similar varibale, the tested varibale will be set to 0 and the other one will come out clean in the check
dst[i] = 0;//eliminating the varibale in that specific address
}
}
return dst [i];
but it doesn't seems to work and have no idea where it is going wrong.
any help or clue will be appreciated .
I noticed that you're using sizeof(src) within a function that takes int src[] as a parameter. This is not doing what you think it is doing. In C, the size of arrays is not passed to functions along with the array itself (unlike some other languages you may be familiar with). You will have to pass the actual size as a separate parameter.
Also, some printf() statements will definitely help your debugging efforts. Make sure values are what you think they should be. Hopefully you have access to an interactive debugger, that would probably be really useful for you too.
In C you cannot declare a function that takes a parameter that is an array. When you use an array declarator as a function parameter the type is silently adjusted to the corrsponding pointer type. Any explicit array size (if specified) is discarded.
In other words, when you use this:
int RemoveDup (int src[],int dst[])
it is exactly equivalent to this:
int RemoveDup( int *src, int *dst )
It should now be obvious why sizeof(src)/sizeof(int) doesn't do the calculation that you wanted it to do.
well in fact it is possible to make a function recieve an array and not a pointer (given of course the size of the array is pre-defined).
so you can use:
int RemoveDup(int src[M],int dst[N]){
.
.
.
return whatever;
I will agree though that using pointers is better.
In my opinion you should write a recursive function to do that using of course pointers.
so that the next call is (*src+1) so you look at the next cell.
the exit condition is then:
if (sizeof(src) == 0) {
//exit recursion statement.
}