Why am I getting "undefined reference to" error? - c

The code below throws an error "undefined reference to 'poredi'".
Everything is defined in this single c file (aside from the c libs in include).
'poredi' is just a function, of which I define a prototype right below the typedef and then I impelement it lower in the file.
Looking at some of the similar questions I can say that it is compiled on Windows 10 using the MinGW C compiler through the CodeBlocks IDE without any additional arguments for compiling.
I am a total C noob so any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char ime[20];
char prezime[20];
char registracija[10];
int dRod;
int mRod;
int gRod;
char datumIzdavanja[10];
} vozac;
void poredi(vozac *vozaci, int linije);
int nlines(char *datoteka);
void napuni(FILE *ulaz, vozac *vozaci, int lines);
int main(){
int lines = nlines("Registar.in");
FILE *ulaz = fopen("Registar.in", "r");
int i;
FILE *izlaz = fopen("Najmladji.out", "w");
vozac *vozaci = calloc(lines,sizeof(vozac));
napuni(ulaz,vozaci,lines);
fclose(ulaz);
poredi(vozaci,lines);
for (i = 0; i < 5; i++){
printf("\n%s %s (%d.%d.%d)", vozaci[i].ime, vozaci[i].prezime, vozaci[i].dRod, vozaci[i].mRod, vozaci[i].gRod);
}
fclose(izlaz);
return 0;
}
int nlines(char *datoteka){
FILE *ulaz = fopen("Registar.in", "r");
int brojac = 0;
while (!feof(ulaz)){
char ch = fgetc(ulaz);
if (ch == '\n') brojac++;
}
fclose(ulaz);
return brojac;
}
void napuni(FILE *ulaz, vozac *vozaci, int lines){
int i;
char *linija = calloc(70, sizeof(char));
char *token;
char *token2;
char *znak;
char *znak2;
for (i= 0; i < lines; i++){
fgets(linija,70,ulaz);
token = strtok(linija," ");
strcpy(vozaci[i].prezime, token);
znak = strchr(vozaci[i].prezime,',');
*znak = 0;
token = strtok(NULL," ");
strcpy(vozaci[i].ime, token);
znak2 = strchr(vozaci[i].ime, ';');
*znak2 = 0;
token = strtok(NULL, " ");
strcpy(vozaci[i].registracija, token);
token = strtok(NULL, " ");
token2 = strtok(token, ".");
vozaci[i].dRod = atoi(token2);
token2 = strtok(NULL, ".");
vozaci[i].mRod = atoi(token2);
token2 = strtok(NULL, ".");
vozaci[i].gRod = atoi(token2);
token = strtok(NULL, " ");
strcpy(vozaci[i].datumIzdavanja, token);
}
void poredi(vozac *vozaci, int linije){
int sortirano = 1;
vozac buffer;
while (sortirano){
sortirano = 0;
for (i = 0; i < linije; i++){
if (vozaci[i].gRod > vozaci[i+1].gRod){
buffer = vozaci[i];
vozaci[i] = vozaci[i+1];
vozaci[i + 1] = buffer;
sortirano = 1;
}
else if (vozaci[i].gRod == vozaci[i + 1].gRod){
if (vozaci[i].mRod > vozaci[i + 1].mRod){
buffer = vozaci[i];
vozaci[i] = vozaci[i+1];
vozaci[i + 1] = buffer;
sortirano = 1;
}
else if (vozaci[i].mRod == vozaci[i + 1].mRod){
if (vozaci[i].dRod > vozaci[i + 1].dRod){
buffer = vozaci[i];
vozaci[i] = vozaci[i+1];
vozaci[i + 1] = buffer;
sortirano = 1;
}
}
}
}
}
}
}

You have poredi() defined inside napuni(). Nested functions is not valid in ISO C but gcc allows it as an extension. I doubt you actually intended to use nested functions but misplaced of braces. Basically remove one brace } from the end of your source file add it above the definition of poredi().
A better indentation would have help avoid such surprises.

Related

How to correctly manage output of strtok_r?

Let's assume I have a char buffer with data separated with char ":";
char pt[256] = "pt:ct:mac";
char *plain_text;
char *cipher_text;
char *mac;
char *next = NULL;
char *tokens = NULL;
const char sep[2] = ":";
tokens = strtok_r(pt, sep, &next);
do
{
if(i == 0)
{
int ln = strlen(tokens);
plain_text = (char*)malloc(ln * 1);
i++;
continue;
}
if(i == 1)
{
int ln = strlen(tokens);
cipher_text = (char*)malloc(ln * 1);
i++;
continue;
}
if(i == 2)
{
int ln = strlen(tokens);
mac = (char*)malloc(ln * 1);
i++;
continue;
}
}
while((tokens = strtok_r(NULL, sep, &next)) != NULL);
free(plain_text);
free(cipher_text);
free(mac);
, so the question is how in the right way to deal with strtok_r output results.
Basically, the main aim is to get the results out of pt string, and put it in the dynamic containers. Since, I don't know the size of plain_text and cipher_text.
Is it the right way to program it?
Apart from that, if do see some minor mistakes or something can be written with better practices please do let me know ;) Thank you!
I would do it with array of pointers.
char pt[256] = "pt:ct:mac";
char *next = NULL;
char *token = NULL;
char *tokens[3] = {NULL};
const char sep[2] = ":";
token = strtok_r(pt, sep, &next);
while(token)
{
int ln = strlen(token);
tokens[i]= (char*)malloc((ln * sizeof(char)) + 1);
strcpy(tokens[i],token);
i++;
token = strtok_r(NULL, sep, &next);
}
for (int i = 0; i< 3 && tokens[i]; i++) {
free(tokens[i]);
tokens[i] = NULL;
}

Parsing nmea csv in c++/c for microchip

How can I parse a comma separated char string? I've tried using strtok but I can't get it working.
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char *input[8];
int i = 0;
for( i=0;i<8;i++)
{
input[i] = p;
p = strtok(NULL, ",");
}
Ideally I'd like to be able to set a variable to the string. Such as
if (i == 0){
string type = $GNRMC;
}
if (i == 1){
float thisnum = 011802.00
}
etc.
This is being written for a pic so I can't use vectors.
You're upper snippet is working for me, besides two minor issues:
buf should be str2
your array of char pointers is too small to hold all substrings
For the second one, you need to convert your substring to the correct type first.
__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
#define NUM_SUBSTRINGS 13
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char * input[NUM_SUBSTRINGS];
int i = 0;
for(i=0; i<NUM_SUBSTRINGS; i++)
{
char *type = NULL;
float thisnum = 0.0;
if (i == 0){
type = p;
}
if (i == 1){
thisnum = strtof(p, NULL);
}
if(p != NULL)
printf("String %s, type: %s, num: %f\n", p, type, thisnum);
input[i] = p;
p = strtok(NULL, ",");
}
return 0;
}

Segmentation Fault with strlen

I am getting a segmentation fault error. When I comment out "wordlength = strlen(token);" it runs fine. I don't know why it the seg fault happens when I assign a strlen(token) just fine to an int a few lines before this one. I would appreciate any help possible.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define char_max 60
int main(int argc, char *argv[])
{
FILE *fp = fopen(argv[2],"r");
char **wordlist;
int row = 1;
int i;
char temp[100];
char *token;
int wordlength;
int lengthcounter;
wordlist = (char**)malloc(row*sizeof(char*));
for(i = 0; i < row; i++)
{
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
}
while(fgets(temp, sizeof(temp), fp) != NULL)
{
lengthcounter = 0;
wordlength = 0;
token = strtok(temp, " ");
strcat(wordlist[row-1], token);
printf("%s\n", wordlist[row-1]);
lengthcounter = strlen(token);
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
printf("The lengthcounter is %d\n", lengthcounter);
}
free(wordlist);
fclose(fp);
return 0;
}
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
What happens in the last iteration of the loop when token is NULL? You pass it to strlen anyway.
Also, this is almost certainly wrong:
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
You're allocating space for pointers, not characters. So why sizeof(char*)? Also, don't cast the return value of malloc. This is C, not C++.

Strtok using dynamic memory

I have the following code, and I need help getting and storing the last token. Right now the code tokenizes after every space, but when it gets to the end of my text file, it doesn't tokenize the last value. I'm pretty sure I need to have the token before the malloc statements, but when I add it in front, I get a seg fault. Does anybody know the issue? Initialized myStruct.extras = NULL above because of realloc; it is a char **.
token = strtok(fileArrayPTR[p],"X");
while (token!= NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL," ");
myStruct.dimensions[1] = strtol(token,&ptr,10);
}else{
myStruct.extras = realloc(myStruct.extras,(extraCounter + 1) * sizeof(char *));
myStruct.extras[extraCounter] = malloc(strlen(token)+1);
strcpy(myStruct.extras[extraCounter],token);
token = strtok(NULL," ");
extraCounter++;
}
}
edit: forgot to put the incremented counter
This is (the second version of) the code from the question:
token = strtok(fileArrayPTR[p],"X");
while (token!= NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL," ");
myStruct.dimensions[1] = strtol(token,&ptr,10);
}else{
myStruct.extras = realloc(myStruct.extras,(extraCounter + 1) * sizeof(char *));
myStruct.extras[extraCounter] = malloc(strlen(token)+1);
strcpy(myStruct.extras[extraCounter],token);
token = strtok(NULL," ");
extraCounter++;
}
}
This is not a self-contained program. We can improve it by:
Removing the structure.
Showing corresponding variable declarations.
Converting it into a simple main().
Those changes lead to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int extraCounter = 0;
char **extras = 0;
int tempCounter = 0;
char *ptr = 0;
char data[] = "10X16 something another-thing";
char *token = strtok(data, "X");
int dimension1 = strtol(token, &ptr, 10);
int dimension2 = -1;
while (token!= NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL," ");
dimension2 = strtol(token, &ptr, 10);
tempCounter++;
}
else
{
extras = realloc(extras, (extraCounter + 1) * sizeof(char *));
extras[extraCounter] = malloc(strlen(token)+1);
strcpy(extras[extraCounter], token);
token = strtok(NULL, " ");
extraCounter++;
}
}
printf("Dimensions: %dx%d\n", dimension1, dimension2);
for (int i = 0; i < extraCounter; i++)
printf("%d: [[%s]]\n", i, extras[i]);
return 0;
}
And when run, it produces:
Dimensions: 10x16
0: [[16]]
1: [[something]]
2: [[another-thing]]
Is there a problem with that code? Yes, the code for the dimension2 doesn't reinvoke strtok(), so 16 is processed twice, once as a dimension and once as a string. Probably not what's wanted. Hence:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int extraCounter = 0;
char **extras = 0;
int tempCounter = 0;
char *ptr = 0;
char data[] = "10X16 something another-thing";
char *token = strtok(data, "X");
int dimension1 = strtol(token, &ptr, 10);
int dimension2 = -1;
while (token != NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL, " ");
dimension2 = strtol(token, &ptr, 10);
tempCounter++;
}
else
{
extras = realloc(extras, (extraCounter + 1) * sizeof(char *));
extras[extraCounter] = malloc(strlen(token) + 1);
strcpy(extras[extraCounter++], token);
}
token = strtok(NULL, " ");
}
printf("Dimensions: %dx%d\n", dimension1, dimension2);
for (int i = 0; i < extraCounter; i++)
printf("%d: [[%s]]\n", i, extras[i]);
return 0;
}
Compilation:
gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror ss.c -o ss
Output:
Dimensions: 10x16
0: [[something]]
1: [[another-thing]]
Looks better...

Get substrings from string in C

I have such string (it's a string that represents a system path actually):
./home/user/dir1/dir2/
And now, I would like to be able to create presented directory tree, so I need to create home, user, dir1, dir2.
I know how to create dirs in C in Linux, but have troubles with chopping off the string. Basically, what I need now is to have an array of strings:
tmp[0] = "./home/";
tmp[1] = "./home/user/";
tmp[2] = "./home/user/dir1/";
tmp[3] = "./home/user/dir1/dir2/";
and if I will hav such array it would be pretty easy to make presented dir tree but how to split the string in that way?
This is a bit naive but it should get you started. It will handle paths that may or may not have a trailing / and also escaped paths, such as ./home/some\/user/dir1/dir2
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char path[] = "./home/user/dir1/dir2";
char *start = path;
char *end = start + strlen(path);
while (start < end) {
char *slash = strchr(start, '/');
if (slash) {
if (slash > path && *(slash - 1) == '\\') {
start = slash + 1;
continue;
}
*slash = 0;
}
if (strcmp(start, ".") != 0) {
/* Use 'path' for mkdir here */
/* mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) or whatever */
printf("going to make %s\n", path);
}
if (!slash) {
break;
}
*slash = '/';
start = slash + 1;
}
return 0;
}
I'd go for Sean's advice as "You should just exec() mkdir -p ... and save yourself the headache."
However if C is necessary, there you go:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE 100
int main(){
char s[] = "./home/user/dir1/dir2/";
char** tmp;
int i, j;
int size = 0;
char* token;
/* count the '/' characters */
char c = s[0];
int count = 0;
i = 0;
while (c != '\0'){
if (s[i] == '/')
count++;
i++;
c = s[i];
}
size = i;
/* ready the tmp array */
tmp = (char**)malloc(count);
for (i = 0; i < count; i++){
tmp[i] = (char*)malloc(BUF_SIZE);
for (j = 0; j < BUF_SIZE; ++j)
tmp[i][j] = '\0';
}
/* special treatment for our first tmp[] */
tmp[0][0] = '.';
tmp[0][1] = '/';
i = 0;
/* tokenize the main string */
token = strtok(s, "./");
while (token != NULL){
if (i > 0)
strcat(tmp[i], tmp[i - 1]);
strcat(tmp[i], token);
strcat(tmp[i], "/");
printf("%s\n", tmp[i]);
token = strtok(NULL, "/");
i++;
}
/* clean up */
for (i = 0; i < count; i++)
free(tmp[i]);
getchar();
return 0;
}
The output is:
./home/
./home/user/
./home/user/dir1/
./home/user/dir1/dir2/
I would use strtok to parse the directory names from the string using "/" as the delimiter.
see: http://www.cplusplus.com/reference/cstring/strtok/
Heres how I did it:
#include <stdio.h>
#include <string.h>
// Count the number of times the character appears in the string
size_t countInstances(char* str, char token) {
size_t count = 0;
while(*str) {
if(*str == token) {
count++;
}
str++;
}
return count;
}
int main() {
char path[] = "./home/user/dir1/dir2/"; // strtok might segfault if this is a pointer (rather than an array)
size_t count = countInstances(path, '/');
char** dirs = malloc(sizeof(*dirs) * count);
char* dir;
size_t i = 0;
dir = strtok(path, "/");
while(dir && i < count) {
dirs[i] = dir; // store reference
printf("%s\n",dir);
dir = strtok (NULL, "/");
i++;
}
free(dirs);
return 0;
}
output is:
.
home
user
dir1
dir2

Resources