I typed these codes + I get a segmentation fault. I am trying to make my very own special version of strtol:
struct optional_int {int Value; char IsNull;};
struct optional_int StrToHex(char Str[]) {
const char Hex[0x10] = "0123456789ABCDEF";
unsigned int Chr = 0x00,i,j,Number = 0x00;
unsigned char IsNull, IsNegative;
if(Str[0x0] == '-') {
IsNegative = 0x1;
int N_C_Char = 0;
while( Str[N_C_Char] != '\0' ) {
Str[N_C_Char]=Str[N_C_Char+1];//right here
N_C_Char++;
}
}else{IsNegative=0;}
printf("%sfas", Str);
for(i = strlen(Str); i > 0; i--){
unsigned int Successes = 0x0;
for( j = 0; j < 0x10; j++ ) {
if( Str[Chr]==Hex[Chr]) {
Number+=((pow(0x10, i))*j);
Successes++;
}
}
if(Successes!=1) {
IsNull = 1;
}else{
IsNull = 0;
Number = 0;
}
Chr++;
}
if(IsNegative == 1) {
return (struct optional_int){ Number, IsNull};
}else{
return (struct optional_int){-Number, IsNull};
}
}
int main(int argc, const char *argv[]) {
printf("asdf %x\n", StrToHex("-535").Value);
}
Whenever I give it some negative numbers, it gave me a segmentation fault core dump but I have located the issue.
Ok, so I figured it out. The issue is indeed the string you pass to the function. When you write "-535" the string is allocated in the data section of the program and you are not allowed to write it. When the number is negative you try to modify that string by shifting the digits over the - sign. That's why it crashes on negative numbers only.
int main(int argc, const char *argv[]) {
char c[200];
strcpy(c, "-535");
printf("asdf %x\n", StrToHex(c).Value);
}
This snippet works for me in the main function. You will never be able to pass constant strings to the function or pointers that refer to this kind of strings:
char c[200] = "-535";
StrToHex(c);
will also crash.
You must provide a memory location where you have write permissions.
Another workaround to your issue would be to not change the string to delete the - but write your code to just ignore it :)
Related
I just started to learn C and need some helps. I already compiled my code and fixed all warnings that occur. However, when I run my program it says 'Segmentation Fault' and this is my code.
#include <stdio.h>
#include <string.h>
char *sorting(char word[51], int n)
{
for (int i = 0; i < n; i++) {
for (int j = i+1; j < n; j++) {
if (word[i] > word[j]) {
char temp = word[i];
word[i] = word[j];
word[j] = temp;
}
}
}
return word;
}
From above, I just sort the word in order to use in strcmp.
First I will read file that contains jumbled words. Next read dictionary's file. Then I will check whether two words are the same.
int main(int argc, char **dict, char **jambles)
{
const char *j = jambles[1];
FILE *jambles_file = fopen(j, "r");
char jambles_words[51];
while (fgets(jambles_words, sizeof(jambles_words), jambles_file)) {
int count = 0;
const char *d = dict[1];
FILE *dict_file = fopen(d ,"r");
char dict_words[51];
printf("%s", jambles_words);
while (fgets(dict_words, sizeof(dict_words), dict_file)) {
int length_jambles = strlen(jambles_words);
int length_dict = strlen(dict_words);
char *j_ = jambles_words;
char *d_ = dict_words;
const char *sort_jambles = sorting(j_, length_jambles);
const char *sort_dict = sorting(d_, length_dict);
if (length_jambles == length_dict) {
int compare = strcmp(sort_jambles, sort_dict);
if (compare == 0) {
printf("%s", dict_words);
count++;
}
}
else if (count == 0) {
printf("NO MACTHES");
}
}
printf("\n");
}
return 0;
}
I still don't know what are the mistakes of my code even I already search on the internet for the causes of Segmentation Fault.
I suspect the root cause is that you misunderstand how command-line arguments are passed to C programs. When you run ./a.out foo bar and it calls into int main(int argc, char **argv, char **envp), "foo" will be in argv[1] and "bar" will be in argv[2]. envp will just contain environment variables like "TERM=xterm" and "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin". You appear to think that "bar" will instead end up in envp[1], which is incorrect.
The more immediate cause is likely that because of the above, your call to fopen is failing due to a file called "TERM=xterm" or something not existing, and so returning NULL, which you then pass to fgets blindly. In general, it's Undefined Behavior to pass null pointers to any standard library function that doesn't specifically say what doing so will do.
When I call mysql_init(mysql);, it is overwriting a char array. I do not understand what I am doing wrong. My code:
void prepare_mysql(MYSQL *mysql) {
mysql_library_init(0, NULL, NULL);
mysql_init(mysql);
}
void get_uid(char *src, char *dst) {
int i, len, count = 0;
len = strlen(src);
for(i = 0; i != len; i++) {
if(src[i] == '-') { // iterate until a - sign is found
break;
}
dst[count] = src[i]; // save char into dst
count++;
}
dst[count] = '\0'; // add null char at the end of char array, otherwise everything will explode...
// dst is now: 389302
}
int main(int argc, char *argv[]) {
// argv[1] is for example: 389302-8232
char uid;
get_uid(argv[1], &uid);
printf("uid = %s\n", &uid); // prints: 389302 (correct)
MYSQL conn;
prepare_mysql(&conn);
printf("uid = %s\n", &uid); // prints: 3 (the first char only.. why?)
mysql_close(&conn);
mysql_library_end();
return 0;
}
If I call the get_uid function after I call mysql_init, I cannot call mysql_close(&conn) because I get a Segmentation fault. Please help, I cannot understand..
Edit:
I have added this in main:
char *uid = malloc(strlen(argv[1]));
And later in main, I call free(uid);. Now it seems to be printing correctly everywhere before I call free.
You don't have a char array - uid is only a char.
I am try to write a user defined function which will do exactly what strcpy() library function do. But although there is no error, my program crashes and not copying second string to first string. What's wrong with this code and how to fix it?
#include<stdio.h>
#include<string.h>
int main(){
char *ch1="abcd";
char *ch2="efgh";
str_cpy(ch1,ch2);
}
str_cpy(char *c1,char *c2){
int i=0;
while(c1[i]!='\0'){
i++;
}
printf("%c",*(c1+3));
int k;
for(k=0;k<=i;k++){
*(c1+k)=*(c2+k);
}
}
String literals are generally put into read only area, that's why the program crashed when you are writing into c1. The destination string needs to be an array or allocated buffer:
char c1[5];
str_cpy(c1, c2);
Also, in the function, it looks you are copying c2 to c1, but you are counting the length of c1, you should count the length of c2 instead:
// copy string c2 to c1
void str_cpy(char *c1, const char *c2){
int i=0;
while(c2[i]!='\0'){
i++;
}
int k;
for(k=0;k<=i;k++){
*(c1+k)=*(c2+k);
}
}
Your program invokes undefined behavior because you are trying to write to a string literal. String literals can be stored in read only memory, which is probably the case on your system, hence causing a crash.
Note that your string copying function can perform the copy in a single loop:
char *str_cpy(char *c1, const char *c2) {
for (int i = 0;; i++) {
c1[i] = c2[i];
if (c1[i] == '\0')
return c1;
}
}
You can verify the behavior with a modified main:
#include <stdio.h>
char *str_cpy(char *c1, const char *c2) {
for (int i = 0;; i++) {
c1[i] = c2[i];
if (c1[i] == '\0')
return c1;
}
}
int main(void) {
char buf[20];
char *ch2 = "Hello world\n";
printf("%s\n", str_cpy(buf, ch2));
return 0;
}
Here is a possible rework of your code, which doesn't have to pre-define buffer size (c1). You simply pass the buffer address. Also, please note that such buffer has to be freed once used (for example, if declared in local scope, not in main()):
#include <stdio.h>
#include <stdlib.h>
char *str_cpy(char **c1, const char *c2) {
int i, size = 0;
for(i = 0; ; i++)
if(c2[i] == '\0')break;
size = i + 1;
if(!(*c1 = realloc(*c1,size*sizeof(char))))
return *c1;//or devise some more sophisticated error handling
for (i = 0;; i++) {
(*c1)[i] = c2[i];
if (c2[i] == '\0')
return *c1;
}
}
int main(void){
char *ch1 = malloc(1); //you're responsible for freeing it, once used
char *ch2 = "Hello, everybody in the neighborhood!";
printf("%s\n",str_cpy(&ch1,ch2));
free(ch1);
return 0;
}
Please, also note you don't need to #include <string.h>
I have two string shown below:
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
In a part of the program I used the following code where it increments the pointers for both strings to point to the next characters.
ch_A = text_to_compare[i++];
ch_B = dictionary[j++];
Why is pointer j being incremented but pointer i is remaining as it was?
Thanks in advance.
EDIT: Below is the full code. The aim of this project is to compare a string with a list of words. Integer i is not incrementing only after the program enters the else statement.
#include <string.h>
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
int bring_characters(char pdata *, char pdata *, char ch_A, char ch_B, char i,
char j);
void main(void) {
unsigned char ch_A;
unsigned char ch_B;
unsigned char i = 0;
unsigned char j = 0;
char pdata N1;
char pdata N2;
int result;
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j];
result = bring_characters(&N1, &N2, ch_A, ch_B, i, j);
if (result == 0) {
while (1)
;
}
else {
while (1)
;
}
while (1)
;
}
int bring_characters(char pdata *N1, char pdata *N2, char ch_A, char ch_B,
char i, char j) {
do {
if (ch_A == ch_B) {
ch_A = text_to_compare[i++]; // take a caharacter from the text
ch_B = dictionary[j++];
if ((ch_A == '\0') && ((ch_B == ',') || (ch_B == '.'))) {
while (1)
; // load idata-------------------------------------------------------------------------------------------------
}
}
else {
i = 0; // refresh pointer
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j++];
}
} while (ch_B != '.');
return (0);
}
Whew, there's a lot going on here! Now that you've added the full code it looks like in your attempt to move on to the next word you have prevented yourself from moving on.. you'll need to do some major revisions to get this guy working.
The first thing you need to do is figure out how you would do this on paper, then step by step try to reproduce that in your code.
Here's a function to kickstart you:
int find_next_match(char toFind, int startingPosition, char* mainString){
int counter = startingPosition;
char buf = mainString[counter];
while(buf != NULL){
if (buf == toFind){
return counter;
}
counter++;
buf = mainString[counter];
}
return -1; //error
}
You can use something like this to find the next instance of the first character in your string, then you can implement a loop to determine if that is a match.
Good luck, you can do it!
I am writing a function which takes in the integer value and the pointer to a character.
the function converts the integer value into binary and stores it in the char pointer.
the char pointer is 16 bytes long.
Snippet of code:
void int2bin(u_int16_t addr_IP, char *Binary)
{
int count;
printf("IP1add = %d \n", Binary);
for (count = 0; count < 16; count++) {
if(addr_IP>0)
*(Binary + 15-count) = addr_IP & 0x1 ? '1':'0';
else
*(Binary + 15-count) = '0';
addr_IP>>=1;
}
}
int main(int argc, char *argv[])
{
u_int16_t senderIP_16[], u_int16_t receiverIP_16[];
char sender_IP_hi[16], sender_IP_low[16];
int2bin(senderIP_16[0], &sender_IP_hi);
int2bin(senderIP_16[1], &sender_IP_low);
}
In the first call to the function, it returns correct values. But in the second pass, the value of first pass is appended to the second pass, i.e length of sender_IP_low becomes 32.
How can I resolve this?
Thanks
It looks like you're printing sender_IP_low as a string, and since it is not null-terminated, the print routine continues to print the adjacent buffer, sender_IP_hi. And you're probably just lucky that the print routine finds a zero and stops before a segmentation fault.
One quick fix is:
void int2bin(u_int16_t addr_IP, char *Binary) {
...
Binary[16] = 0; // terminate the string before returning
}
...
char sender_IP_hi[17], sender_IP_low[17]; // +1 for null terminator
Although, there are a few other things that could be fixed in your implementation, I just wanted to focus on an answer to your original question.
If you are printing the arrays with printf():
void int2bin(u_int16_t addr_IP, char *Binary)
{
int count;
printf("IP1add = %d \n", Binary);
for (count = 0; count < 16; count++) {
if(addr_IP>0)
*(Binary + 15-count) = addr_IP & 0x1 ? '1':'0';
else
*(Binary + 15-count) = '0';
addr_IP>>=1;
}
// Put the NULL char in the last position
Binary[16] = '\0';
}
int main(int argc, char *argv[])
{
u_int16_t senderIP_16[], u_int16_t receiverIP_16[];
// One more char for storing the terminator character
char sender_IP_hi[17], sender_IP_low[17];
int2bin(senderIP_16[0], &sender_IP_hi);
int2bin(senderIP_16[1], &sender_IP_low);
}