I have something like this in my code:
char *objects[] = {"_muldi3.o","_negdi2.o","_lshrdi3.o","_divdi3.o","_moddi3.o","_udivdi3.o"};
/* Around 127 strings stored above, listed only few here. */
char *divmod_objs[]={"_divdi3.o","_moddi3.o","_udivdi3.o"};
for (i=0;i<obj_count;i++)
{
if (objects[i]==divmod_objs[0])
break;
else
{
/* do something */
}
}
The if statement seems to give "Segmentation fault (core dumped)" so I might be doing something wrong. What is the right way to compare these strings?
Segmentation fault basically means a pointer accessed memory outside of it's bounds (it's allocated memory area).
There is a core mistake in your code, in which you expect the equality operator "==" to compare strings the way it works in Java or C#. But the comparison of strings does not work like that in C. Instead what happens is that you it is trying to compare the [0..(obj_count-1)] char elements of the first string pointed to by "objects" array pointer to the first character of the first string pointed to by the "divmod_objs" pointer. Since the strings in object could end up being > obj_count, in that case a seg. fault is thrown up.
If you want to implement string comparison in C, you need to implement a comparison on character-by-character basis.
Basically You would need a double loop, the outer one would iterate through the string objects, the inner one would iterate within the characters of the individual strings. Plus some bells and whistles to check for array bounds etc.
Write simple function to compare strings:
bool equal(char a[], char b[])
{
for (int i = 0; a[i] != '0' && b[i] != '0'; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
and use it in your code:
char *objects[] = {"_muldi3.o","_negdi2.o","_lshrdi3.o","_divdi3.o","_moddi3.o","_udivdi3.o"};
/* Around 127 strings stored above, listed only few here. */
char *divmod_objs[]={"_divdi3.o","_moddi3.o","_udivdi3.o"};
for (i=0;i<obj_count;i++)
{
if (equal(objects[i], divmod_objs[0]))
break;
else
{
/* do something */
}
}
Related
I'm trying to make a binary number calculator in c and I'm running into issues of my for loops doubling the size of my second array and adding the first array onto the end. I'm really confused because I thought you couldn't increase the size after already declaring it. It is happening in my equation reading function as well but in this ones complement function it's a bit simpler to see. Any ideas of how to fix this?the codethe output
welcome to stack-overflow. From next time please use inline code editor to put your code instead of images. I have taken effort put your code in the answer itself to explain the problem. Please consider this as courtesy. Its very unusual to do it. But as you are a new member, I'm doing it.
// Cole carson's original code from image:
char * onescomp(char x[16], char y[16]){
int i;
for(i=0;i<=15;i++){
if(x[i] == '0'){
y[i] = '1';
continue;
}
else if(x[i] == '1'){
y[i] = '0';
continue;
}
}
return y;
}
int main()
{
char b3n[16]={'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
char cb3n[16];
puts(b3n);
onescomp(b3n,cb3n);
puts(cb3n);
return 0;
}
Answer:
You don't need continue; in if-else blocks.
You need to add '\0' in the last cell of cb3n array. so puts() knows when string ends & stop printing.
so to quickly fix this issue you can create array with extra cell and assign all values as '\0'. so after copying fifteen 1's there will be '\0' in the end. I think in your case those extra zeros being printed might be garbage values. It looks like array is doubling but it isn't, its just printing values beyond allocated memory because '\0' has not been provided.
//Quick fix
int main()
{
char b3n[16]={'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
char cb3n[17]={'\0'}; // <--- quick fix
puts(b3n);
onescomp(b3n,cb3n);
puts(cb3n);
return 0;
}
I just started learning C language and I need some help with a program. Here is the code.
Questions:
What is this? customerData[NUM_FIELDS][FIELD_LENGTH];
Is it a char 2D array?
How do you input data into the array? fgetC, putchar, getchar ?
#include <stdio.h> #include <string.h> #include <stdlib.h>
#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS 9
int main()
{
FILE *data=NULL;
char input[INPUT_LENGTH];
char customerData[NUM_FIELDS][FIELD_LENGTH];
int element=0;
char *next;
char ch;
data= fopen("data.txt","r");
if(data!=NULL)
{
//token=strtok(input,"|");
/*while loop will go through line by line and stored it in an input array*/
while(fgets(input,INPUT_LENGTH,data)!= NULL)
{
next=strtok(input,"|");
while(next!=NULL)
{
//ch=getchar()
//>probably a get char for ch
strcpy(next,customerData[element][strlen(next)]);
/*need to put the values into customer data one by one*/
printf("%s\n",next);
//element+=1;
next=strtok(NULL,"|");
}
//element=0;
}
printf("program is done\n");
}
fclose(data);
return 0;
}
In general, "help me with my code" questions are off-topic on Stack Overflow. In order to keep the question on-topic, I'm going to focus only on the question of how to access 2D char arrays.
Yes, this is a 2D char array. Or, put another way, it's an array with NUM_FIELDS elements, where each element of the array is a char array with FIELD_LENGTH elements.
There are loads of ways to insert data into a 2D char array, but there are probably two I've encountered most often. Which one you choose to use will depend on how you want to think of this array.
Option 1: A 2D array of single chars
The first way to think about this variable is simply as a 2D array of chars - a grid of elements that you can access. Here, you can simply input values using the normal assignment operator. You'll want to make sure that your indexes are in range, or you'll start accessing invalid memory.
//Set a known element that's definitely in range
customerData[1][2] = 'A';
//Loop through all the elements
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
for (int jj = 0; jj < FIELD_LENGTH; jj++)
{
customerData[i][j] = 'B';
}
}
//Set an element from variables
char nextInput = getNextCharFromInput();
if(x < NUM_FIELD && y < FIELD_LENGTH)
{
customerData[x][y] = nextInput;
}
//Bad. This could corrupt memory
customerData[100][60] = 'X';
//Risky without check. How do you know x and y are in range?
cusomterData[x][y] = 'X';
You could certainly write your code by assigning these elements on character at a time. However, the broader context of your program heavily implies to me that the next option is better.
Option 2: A 1D array of fixed-length strings
In C, a "string" is simply an array of chars. So another way to look at this variable (and the one that makes the most sense for this program) is to treat it as a 1D array of length NUM_FIELDS, where each element is a string of length FIELD_LENGTH.
Looking at this this way, you can start using the C string functions to input data into the array, rather than needing to deal character by character. As before, you still need to be careful of lengths so that you don't go off the end of the strings.
Also be aware that all array decay into pointers, so char* is also a string (just of unknown length).
//Set a specific field to a known string, which is short enough to fit
strcpy(customerData[2], "date");
//Loop through all fields and wipe their data
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
memset(customerData[ii], 0, FIELD_LENGTH);
}
//Set field based on variables
if(x < NUM_FIELDS)
{
//Will truncate next if it is too long
strncpy(customerData[x], next, FIELD_LENGTH);
//Will not input anything if field is too long
if(strlen(next) < FIELD_LENGTH)
{
strcpy(customerData[x], next);
}
}
//Bad. Could corrupt memory
strcpy(customerData[100], "date");
strcpy(customerData[1], "this string is definitely much longer than FIELD_LENGTH");
//Risky. Without a check, how do you know either variable in in range?
strcpy(customerData[x], next);
getchar and fgetC both deal with reading characters, from stdout and a file respectively, so can't be used to put data into a variable. putchar does deal with put character into things, but only stdout, so can't be used here.
I have a problem when I try to compare the content of two char arrays.
Sometimes
If the string is less than the actual size of the array, in it there is no sequence of '\0' but often there are unexpected characters (in the xcode debug there was the '\x01' character and in the control loop I use To check if a memory cell of the array was the same as the other, it was not the same). So to overcome this problem I decided to force the user to write the array content exactly as array size(-1): ex. array[3], the users write "hi" (without the ""). So I was wondering if there is a way to compare the two strings (I'm not talking about length but content) without fully filling the array in order to compare the content ofenter code here the two arrays through a simple cycle. (I was thinking of initializing the vector with \ 0 but I do not know if there can be problems)
thanks for the answers
this is an example of the code
}while(sent !=1);
for(contatore=0; contatore<MAXNOME; contatore++){
if(UserName[contatore] == persona.username[contatore]){
controlloUsr++;
}
}
for(contatore=0; contatore<MAXNOME; contatore++){
if(password[contatore] == persona.password[contatore]){
controlloPsw++;
}
}
if(controlloUsr == MAXNOME && controlloPsw == MAXPSW){
return 1;
} else {
return 0;
}
I'm not sure if that's what you're asking, but there is no way to browse an array of chars in C without giving the code a stop sequence, like a \0, or you will browse it forever (well, until a wild segfault appear...)
You can write your own strncmp function for this, something like :
int my_strncmp(char *str1, char *str2, size_t max, char c)
{
size_t n = 0;
while (n < max)
{
if ((str1[n] != str2[n]) || (str1[n] == c) || (str2[n] == c))
return 0;
n++;
}
return 1;
}
This will return 0 if your char c is met, or if the strings are different, or 1 if the string are the same until max char. Just be sure that one of the two conditions is met or you code will crash into a segfault / have undefined behavior, since you will browse out of your allowed memory range.
the function strcmp() and the strncmp() are made for this exact operation,.
You can read the man page for those two functions for all the details.
This question already has answers here:
Correctly allocating multi-dimensional arrays
(2 answers)
Closed 5 years ago.
Here is a shell program I wrote for honing my understanding on C pointer and array. This shell program has the functionalities of reading in commands (execute them in execvp()) and the history feature can store 10 commands (similar to Linux terminal) where "!!" returns latest command and execute, !Nth returns Nth command and execute, otherwise read command and store them in history array. When requested history command doesn't exist, relevant error message printed. For full code reference, see Shell_Program_C.
initialize() method initialize each history character string array with letter 'e' ('e' means empty or string hasn't been assigned) so that I could later check that history string has value or not. readHist() method assign each individual command to the history string array, char** hist which has a size of 10.
My problem is:strcpy(hist[histC], tokens[count])in readHist() is returning 'bad access' here.
Expected behavior: each command should be copied to char** hist as a string of char so that later requested command can be retrieved and executed.
char** initialize() {
char** hist = malloc(10 * sizeof(char *));
for (int i = 0; i < 10; ++i) {
hist[i] = (char *)malloc((MAX_LINE / 2) + 1);
for(int j = 0; j < (MAX_LINE / 2); j++) {
hist[i][j] = 'e';
}
}
return hist;
}
void readHist(char**hist, int histC ,char** tokens, int count) {
histC = (histC - 1) % 10;
for(int i = 0; i < count; i++) {
size_t strlenth = strlen(tokens[i]);
//strcat(hist[histC], tokens[count]);
if(count > 1) {
strcat(hist[histC], tokens[count]);
hist[histC][strlenth] = ' ';
} else {
printf("histC%d", histC);
strcpy(hist[histC], tokens[count]); // bad access or segmentation fault
hist[histC][strlenth] = '\0';
}
}
}
Your SegFault is due to violating the strcat requirement that "The strings may not overlap" This looks like a careless oversight that has big consequences. Specifically, look at cmdargv below:
histCheck(cmdargv, &histCount, cmdargv, count, &isAmp);
You are passing the same array of pointers cmdargv as the parameters that are passed to hist and tokens in your call to:
void histCheck(char**hist, int* histCount, char**tokens, int tcount, int* amp)
In histCheck both hist and tokens point to the same memory that can be seen in a debugger, e.g.
histCheck (hist=0x7fffffffd9b0, histCount=0x7fffffffd9a8, tokens=0x7fffffffd9b0
note the address of both hist and tokens.
This same error is then passed to readHist, e.g.
readHist (hist=0x7fffffffd9b0, histC=1, tokens=0x7fffffffd9b0
which results in your call to strcat attempting to concatenate overlapping strings (the same string), e.g.:
strcat (hist[histC], tokens[count]);
(note: are you sure you want count above?)
which results in your familiar:
Program received signal SIGSEGV, Segmentation fault.
__strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:296
296 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
Now I'm not saying your problems are limited to that (note my comment about he update to count in checkAmp), so you have more work to do. But your SegFault is no longer a mystery.
It appears you intended:
histCheck (hist, &histCount, cmdargv, count, &isAmp);
You will also want to revisit:
strcat (hist[histC], tokens[count]);
which will lead to your very next SegFault. Here it appears you want:
strcat (hist[histC], tokens[i]);
Also, in your rework of your code, pay careful attention to resetting all values with each iteration around your do loop in main to prevent leaving stray values in cmdargv, etc... You will also need some way to free the memory you allocate to prevent leaking memory on subsequent calls to malloc in your various functions.
You will want to make friends with a debugger. There is no way around it, especially when you are chopping the flow up into a number of small inter-related functions to compartmentalize the code. Nothing wrong with that, it just make the debugger all the more important to figure out where the wheels are coming off -- and why...
Rework your code and post any further problems you have. To bandaid the count problem in checkAmp, you may consider something like:
void checkAmp (int *count, char** tokens, int *Amp) {
size_t strlenth = strlen(tokens[*count - 1]);
if((strlenth == 1) && tokens[*count - 1][0] == '&')
{
*Amp = 1;
tokens[*count - 1] = NULL;
*count = *count -1;
} else {
tokens[*count] = NULL;
}
}
(and updating the call to checkAmp as well)
Lastly, while not an error, the standard coding style for C avoids the use of caMelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants. It is a matter of style -- so it is completely up to you...
My code is causing a segmentation fault when accessing an array element even though that element was already accessed without a problem.
int charToInt(char a)
{
int b;
if(isdigit(a))
{
b = a - '0' - 1;
}
if(isalpha(a))
{
b = a - 65;
}
return b;
}
int validPosition(char **array, int r, int c, char* position, int slots)
{
int i,k;
if(strlen(position) == 5)
{
if(!isalpha(position[0]) || !isdigit(position[1]) || position[2]!=' ' || (position[3]!='N' && position[3]!='E' && position[3]!='W' && position[3]!='S')) //lathos gramma
{
printf("\n%s", "Invalid answear.This is an example of a valid answear: A5 N");
return 2;
}
if( charToInt(position[0]) > r - 1 || charToInt(position[1]) > c - 1 )//ama vgainei eksw apo ta oria
{
printf("\n%s", "The position you choosed is out of the bountries...");
return 2;
}
printf("\n%s%c%s","position[3] is: ",position[3], " but it doesn't work >_<"); // position[3] is N
if(position[3] == 'N') //the problem is here <~~~~~~~~~~~~~~~~~~~<
{
printf("\n%s", "come on");
if(charToInt(position[0]) + slots < r)
{
for(i=charToInt(position[0])-1; i<charToInt(position[0])+slots; i++)
{
if(array[i-1][charToInt(position[1])-1] != '.')
{
printf("\n%s", "The position you choosed is not valid because there is oneother ship there");
return 2;
}
}
}
else
{
printf("\n%s", "The ship is going out of the bountries...");
return 2;
}
}
}
}
When position holds the string "A9 N", the printf correctly outputs 'N' for position[3]. For some reason when it tries to do if(position[3] == 'N'), however, a segmentation fault occurs.
Example program run:
Example of positioning: G3 E
Aircraft carrier (5 places), Give location and direction: A9 N
1
position[3] is: N but it doesn't work >_<
Well, based on your updates, it seems you have a variety of problems. For future reference, actually adding in the (possibly simplified) code showing how you were calling the function in question is better than trying to describe it using prose in a comment. There will be less guesswork for the people trying to help you.
If I'm reading your comment correctly, the code that calls validPosition looks something like this:
// "r and c are 9 and 9 in the specific example(rows columns)."
int rows = 9;
int columns = 9;
// "slots=5."
int slots = 5;
// "array is a 2d array and it contains characters(created with malloc)."
char **array = malloc(rows * columns * sizeof(char));
// "i created char position[10] in the function that called this function"
char position[10];
// "and with fgets(position, 10, stdin); i putted A9 N inside it."
fgets(position, 10, stdin);
validPosition(array, rows, columns, position, slots);
The first problem is your description of the allocation of array (I apologize if I misunderstood your comment and this isn't actually what you are doing). It should look similar to the code below for a dynamically sized two-dimensional array used with two subscripting operations (array[index1][index2], as it is in validPosition). Pointers-to-pointers (char **array) act differently than fixed sized multi-dimensional arrays (array[SIZE1][SIZE2]) when you access them that way.
// each entry in array should be a pointer to an array of char
char **array = malloc(rows * sizeof(char*));
for(i = 0; i < rows; i++)
array[i] = malloc(columns * sizeof(char));
You also need to be careful about using position after the fgets call. You should check the return value to make sure it isn't NULL (indicating an EOF or error condition). The string may not be \0-terminated in this case. In fact, all the elements may still be uninitialized (assuming you didn't initialized them before the call). This can lead to undefined behavior.
The next issue is that validPosition does not return a value on every code path. One example is if strlen(position) != 5. The other is if you enter the for loop and array[i-1][charToInt(position[1])-1] != '.' is never true (that is, the ship placement is deemed valid).
As strange as it is for an English speaker to say this to a Greek author, lets ignore internationalization and focus only on the default C local. The checks on position[0] should therefore be sufficient, though you might consider allowing your users to use lowercase letters as well. When converting position[1] from 1-based to 0-based, however, you do not account for the case when it is '0', which will result in charToInt returning -1. Furthermore, you're erroneously doing the subtraction again in the second array subscript of array[i-1][charToInt(position[1])-1].
Similarly, as pointed out by Jite and BLUEPIXY, you are doing two extra subtractions on the result of charToInt(position[0]): one in the for loop initializer (i=charToInt(position[0])-1) and one in the first array subscript of array[i-1][charToInt(position[1])-1].
Once you fix that, you might find that you are sometimes incorrectly telling the user that their selection is invalid. This is because you are checking charToInt(position[0]) + slots < r instead of <= r.
As I mentioned in my comment, one of the accesses to array is very probably the culprit behind your segmentation violation, not position[3] == 'N'. The reason you don't see the output of printf("\n%s", "come on"); is that your stdout appears to be line-buffered and there's no end of line to flush it. It is generally automatically flushed on normal program termination, however you're seg-faulting so that doesn't happen.
Finally, these are only the semantic errors I noticed. Stylistically, the code could also stand to be improved. For instance, it seems you're going to be implementing else if(position[3] == 'E', else if(position[3] == 'W', and else if(position[3] == 'S' clauses with similar logic to your if(position[3] == 'N' clause. This increases the likelihood you'll introduce an error by incorrectly copying-and-pasting and also increases your work later when you need to make a change in four places instead of one.
Since the terminology 'Segmentation Fault' I believe you are on Linux machine.
Use gdb to find the cause of error. Here are the steps.
Compile with additional -g flag (ex. gcc -g my_prog.c)
Run debugger: gdb a.out
Use 'list' command to find the line for break point (eg. first line of your function)
Set breakpoint on that line with: b 25 (if 25 is that line)
Run program with 'run' command
Use command 'next' to execute next line of code
Now the execution will pause on that line, you can examine memory, print variable contents
and stuff. But generally you want to determine on which line the execution fails and what was in which variable.
With a little playing with memory, you will easily find where the problem is. Personally, my code wont work with gdb support.
Perhaps segmentation fault at array[i-1][charToInt(position[1])-1]
i:charToInt(position[0])-1 : charToInt('A') - 1 : -1 <- Array out-of-bounds