why won't VScode compile the function strtok proprely? - c

I started working on VS Ccode recently and I want to use the function strtok() for my project but it won't compile run properly.
I tried compiling this function in an online compiler and it works so apparently the issue is with VScode.
Has anyone ever encountered this issue? And does anyone have a solution to my problem?
#include <stdio.h>
#include <string.h>
char *base(char *line){
char *base, *dividedline;
const char s[3] = " ";
//get the first token
dividedline = strtok(line,s);
printf("%s\n", dividedline);
//get the others
for(int i; i!=3;i++){
dividedline = strtok(NULL,s);
printf("%s\n", dividedline);
if(i == 2){
base = dividedline;
}
return dividedline;
}
printf("finished");
return base;
}
int main()
{
printf("hello world \n");
char *l;
char str[80] = "hi test test";
l = base(str);
return 0;
}
The function is stuck on an infinite loop when I compile it with VScode.
I know the issue is with the line "dividedline = strtok(NULL,s);" and especially with the NULL, but I can't figure out what's wrong.

Your problem is the line:
for(int i; i!=3;i++)
You don't know what the initial value of i is. You should have written:
for (int i = 0; i != 3; i++)
A more defensive style of programming would use:
for (int i = 0; i < 3; i++)
Your loop could still take a long time if i was initialized negative, but would stop immediately if i was positive and bigger than 3. The < idiom is normal in C.

Related

Why Segmentation Faults occur?

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.

c function convert "fffoootoo" to "foto" (leaves out following repeating characters)

The task would be to remove following characters that are repeating from a char array, like "deeeciddeee" -> "decide" or "phhhonne" -> "phone".
I have a function that crashes the console, and I can't spot the bug:
char* my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
}
}
return ret;
}
it is called this way:
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
please help me!
Besides a small bug (you should add the line i--; after last--;, because you're deleting the character at possition i, so what has been the character at i+1 became the new character at possition i. If you don't decrease i, it will be increased and you jump over a character) the code runs perfectly fine IF it is called with
const char* b = "oooat";
char* a = new char[strlen(b) + 1];
for (size_t c = 0; c < strlen(a) + 1; c++) { a[c] = b[c]; }
a = my_unique(a, a + strlen(a));
cout << a;
delete[] a;
Notice that I've used a edit-able copy of the string, as the literal itself is of type const char* and therefor can't be changed at all. And as I said, this works perfectly fine and prints "oat", just as expected, without any crash. So your problem might be that you try to edit a const string literal? In that case you might consider to copy it, as I did, or use std::string (if you code in C++).
There are many beginner mistakes in the code.
Let me point you one by one.
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
When you declare a string like this : char* a="oooat", a is a string literal. The memory for the string is allocated into text section of the program. Which basically means you cannot modify the values inside the strings. You can only read from them. Hence when you are passing pointer a to the function and modifying it, it will result in segmentation fault(Illegal access to memory).
Why do you need a ret pointer here? char* ret=first;
You are passing a pointer and modifying the value inside it. Hence the new data will be reflected in the calling function and we need not return it explicitly. So, it is redundant.
Overall logic can be simplified as well
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MYSTR "ooooat"
void my_unique(char *first, char *last) {
int size = last - first;
int i = 0, j = 0, k = 0;
for (; i < size; i++, j++) {
first[j] = first[i];
// Continue to check how many repetitions are there
while (i + 1 < size && (first[i] == first[i+1])) i++;
}
// In the end terminate the string with a NULL.
first[j] = '\0';
return;
}
int main()
{
char a[] = MYSTR;
my_unique(a, a+strlen(a));
printf("%s", a);
return 0;
}
This is in C. There are simpler ways of doing this in C++, and the code can definitely be condensed but has been left simpler for readability.
#include <stdlib.h>
char* fix(char *input) {
char *lookahead = input;
char *newchar, *ret;
// Determine Max Return String Length
int len = 0;
while (*lookahead != '\0') {
len++;
lookahead++;
};
// allocate max possible memory needed and set the pointers
ret = malloc(len);
newchar = ret;
lookahead = input;
*newchar = *lookahead; // copy the first character
while (*lookahead != 0) {
lookahead++; // incrementing this ptr first starts lookahead at 2nd character and
// ensures the null terminator gets copied before the while loop ends
if (*newchar != *lookahead) { // only copy new characters to new return string
newchar++;
*newchar = *lookahead;
};
};
return ret;
};
I'll try to give my answer so that it makes the as little changes as possible to your original code, while using the simplest methods.
The main problem has already been identified by the previous comments - you cannot alter a string literal.
Also, the line of code
i--;
has to be placed as well, with the reason well clarified above.
While making an editable version of the string may be a good way of fixing the problem, a more straightforward way would be to make it a local string, as such :
char b[] = "oooat";
but doing this will make it incompatible with the return type of your my_unique function (char*). But why would you need a return type in the first place, if you are fixing the string itself?
My final code would look like this :
void my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
i--;
}
}
}
making the function return void.
Hope this helps.

Segmentation fault (11) when using malloc inside a function to form a string

I'm trying to use a function to assign space and fill that space (or at least some of it) with characters to form a string. Within the function I make a call to malloc, and within the same function I assign characters to the given space. The following code gives the general gist of what I'm doing:
#define INITIAL 10
int func(char **s);
int
main(int argc, char **argv) {
char *s;
int n;
n = func(&s);
printf("Done\n");
return 0;
}
int
func(char **s) {
int i;
*s = (char*)malloc(INITIAL*sizeof(char));
assert(*s);
for (i=0; i<5; i++) {
printf("i=%d\n", i);
*s[i] = 'a'; /*'a' is an arbitrary char for this example */
}
return i;
}
The output of this code is:
i=0
i=1
i=2
Segmentation fault: 11
The reason I have my function return an int is because I ultimately want the function to return the length of the string I have formed.
I'm completely unsure why I am getting a segmentation fault; it seems I have assigned enough space to fit the next char in. It also seems weird to me that it stops at i=2.
If anyone could identify the mistakes I have made I would greatly appreciate it!
Instead of
*s[i] = 'a';
you want
(*s)[i] = 'a';
*s[i] is equivalent to *(s[i]). That is, it treats s as an array of strings and gives you the first character of the string at index i.
*s[i] first calculate s[i], which won't be valid place for i!=0, then dereference it and try to put 'a' there. It may cause Segmentation Fault.
Try changing *s[i] to (*s)[i].
Postfix [] has higher precedence than unary *, so *s[i] is being parsed as *(s[i]), which isn't what you want; you want to dereference s and index into the result, so you need to explicitly group the * operator with s: (*s)[i].
You may want to use size_t instead of an int. Or ssize_t if you need the function to return a negative value:
#include <stdio.h>
#include <stdlib.h>
#define INITIAL 10
ssize_t func(char **);
int main(void)
{
char *s;
if((func(&s)) == -1)
{
printf("An error occurred\n");
return 1;
}
printf("Done\n");
free(s);
return 0;
}
ssize_t func(char **s)
{
size_t i = 0;
if ( INITIAL < 1 )
return -1;
if (!(*s = malloc(INITIAL*sizeof(char))))
return -1;
for (i=0; i< 5; i++) {
printf("i=%zu\n", i);
(*s)[i] = 'a';; /*'a' is an arbitrary char for this example */
}
return i;
}

stack smashing detected because of strncpy

I have a problem in a c program. I made a function which tokenizes variables from a textfile and saves them inot a set. The problem is that the strncpy function from string.h behaves strange in my program. I broke my code down to minimal example:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
void tokenizeWord(int *i, char *text);
int main() {
char *text = "hallo 123 test foo bar etc";
int i;
for (i = 0; i < 24; i++) {
switch(text[i]){
case ' ':
i++;
default:
tokenizeWord(&i, text);
}
}
return 0;
}
void tokenizeWord(int *i, char *text) {
bool eow = false;
int start = *i;
int end = start;
if (i != NULL) {
while (*i < strlen(text) && !eow) {
switch(text[*i]) {
case ' ':
end = (*i);
eow = true;
break;
default:
(*i)++;
break;
}
}
char out[8] = "";
strncpy(out, text+start, end);
out[end-start] = '\0';
printf("%s\n", out);
}
}
The first variable which is printed out is "hallo", what is totally correct behaviour. The secound variable already contains "123 test". But because I set the \0 after 123 the rest won't get printed. Immediately after the print, I get a * stack smashing detected * abort. I think the problem is, that the strncpy function tries to write more than 8 characters, but i told the function to print from text at position 6 to 9. So why strncpy tries to copy more than three characters?
I don't have much experience in C programming and tried many things, like debugging and printouts to find the problem, but I have no clue yet. I hope somebody can help me.
Change the following
strncpy(out, text+start, end);
To
strncpy(out, text+start, end-start);
if start = 6 and end = 9 then you are copying 9 bytes and not 3.
Read More about Stack Smashing.

What line is at fault -- segfault, that is...?

I'm relatively new to C (and completely new to StackOverflow - hey guys!), and this segfault has been giving me no surcease of sorrow for the past few hours (DevC++ on a windows machine). It's just a simple palindrome prime program, but it's really giving me a hard time. I'm not generally a novice programmer like it seems here, but... Good god. Now I remember why I wanted to get away from C++ and to Python so quickly.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
FILE *outputFile;
char buffer[81];
char* strrev();
int bytesWritten;
char* strI = 0;
char *strrev(char str[])
{
char *p1 =NULL;
char *p2 =NULL;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
main()
{
int isPrime(int);
int i,j;
outputFile = fopen("DD:OUTPUT", "w");
if (outputFile == NULL)
{
printf("open error: %d/%s\n", errno, strerror(errno));
exit(99);
}
for (i=1; i<15000; i++)
{
if (isPrime(i)==1)
{
bytesWritten = sprintf(buffer,"%d is primepal!\n",i);
fwrite(buffer, 1, bytesWritten, outputFile);
}
}
fclose(outputFile);
return 0;
}
int isPrime(int myInt)
{
int loop;
for (loop = 2; loop < myInt/2+1; loop++)
sprintf(strI, "%s%d", 10, myInt);
{
if (myInt%loop==0 && (atoi(strrev(strI))-myInt)==0)
{
return 0;
}
return 1;
}
}
I apologize ahead of time if this is a dumb question, and the answer is very obvious -- but I've officially hit the limit where no matter how logical an answer, I've been coding the same problem for too long for it to make any sense. And also, segfaults are horrible beasts. Thank you ahead of time for anything you have to offer!
~ Jordan
The line sprintf(strI, "%s%d", 10, myInt); is likely crashing.
You have not allocated any space for strI, it's defined as char* strI = 0; Make it a char[64] , or a suitable size.
You're giving the wrong arguments to sprintf, "%s%d" says the first parameter should be a string ("%s") , but you give it an int. Change %s to %d
Some other issues:
Don't use *p1 ^= *p2; hack to to swap variables, there's many cases where this does not work. Do it properly with a temp variable.
main() calls isPrime(), but there's no prototype for isPrime at that time. Place int isPrime(int myInt); somewhere before main().
The prototype for your strrev function should be char *strrev(char str[]); and not char *strrev()
Segfaults don't have to be as bad as you're experiencing. Compile the program with debugging symbols (add -g to gcc) and run it in gdb. After the segfault, type bt in gdb and press enter. It will tell you the exact line of your segfault.
for (loop = 2; loop < myInt/2+1; loop++)
sprintf(strI, "%s%d", 10, myInt);
{
if (myInt%loop==0 && (atoi(strrev(strI))-myInt)==0)
You might want to double-check where you've got that brace in relation to the for. This isn't python, and indentation alone doesn't cut it.

Resources