Segmentation fault when parsing c string into pointer array - c

The function makearg is supposed to count the number of words in a char array and also break each word up into their own spot in a pointer array.
Segmentation fault seems to be a problem with the strncpy function.
int makearg(char s[], char ***args);
int main(){
char **args = (char**)(malloc(100));
char *str = "ls is a -l file";
int argc;
argc = makearg(str, &args);
printf("%d", argc);
printf("%c", '\0');
int i;
for(i = 0; i < argc; i++){
puts(args);
printf("%c", '\n');
}
return 0;
}
/////////////////////////////////////////
int makearg(char s[], char ***args){
int argc = 0;
int charc = 0;
int wordstart = 0;
while(1){
if(s[charc] == '\0'){
strncpy(*args[argc], s + wordstart, charc - wordstart);
args[argc][(charc - wordstart) + 1] = '\0';
argc++;
break;
}
if(s[charc] == ' '){
strncpy(*args[argc], s + wordstart, charc - wordstart);
args[argc][(charc - wordstart) + 1] = '\0';
wordstart = charc + 1;
argc++;
charc++;
}
else{
charc++;
}
}
return argc;
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int makearg(const char s[], char ***args);
int main(void){
char **args = NULL;
const char *str = "ls is a -l file";
int argc = makearg(str, &args);
printf("argc : %d\n", argc);
int i;
for(i = 0; i < argc; i++){
puts(args[i]);
free(args[i]);
}
free(args);
return 0;
}
int wordCount(const char *s){
char prev = ' ';
int wc = 0;
while(*s){
if(isspace(prev) && !isspace(*s)){
++wc;
}
prev = *s++;
}
return wc;
}
int makearg(const char s[], char ***args /*out*/){
int argc = wordCount(s);
int len;
if(argc == 0){
*args = NULL;
return 0;
}
*args = malloc(argc * sizeof(char*));
argc = 0;
while(1){
while(isspace(*s))
++s;
if(EOF==sscanf(s, "%*s%n", &len))
break;
(*args)[argc] = malloc(len + 1);
strncpy((*args)[argc], s, len);
(*args)[argc++][len] = '\0';
s += len;
}
return argc;
}

You allocated space for the args array of pointers, but you never allocate space for the strings you intend to store in them, so when you try to store the strings in makearg, you are interpreting whatever random garbage is there as a pointer, and that's not going to work.
Also, you only allocate 100 bytes for the pointer array -- it's not clear how many
words you expect to be able to split, but the malloc call should probably look more like
char **args = malloc(MAX_WORDS * sizeof(char *)); /* no cast required */
then follow that with a loop to do MAX_WORDS more malloc calls, in order to initialize args with valid pointers.

Related

reversing word. (null terminated c string char array). why isn't it working

am trying to reverse a char array and print it using %s. but its not working. am not getting anything printed. why is that? my code is pretty simple/
char* reverse(char* word){
int i = 0;
int length=0;
while (word[i] != '\0'){
i++;
}
length = i;
char* temp_word = malloc(length* sizeof(char));
for (i = 0; i < length; i++){
temp_word[i] = word[length - i];
word[i] = temp_word[i];
}
return word ;
}
temp_word[i] = word[length - i];
should probably be
temp_word[i] = word[length - i - 1];
If word[] is 3 characters long, word[3] is actually the null terminator.
This works ... you did not allocate space for Null terminator ... and you are overwriting by doing this 'word[i] = temp_word[i]' ...
#include <stdio.h>
#include <stdlib.h>
char *reverse(char *);
int main()
{
char sWord[10] = "PHONE";
char *temp = NULL;
printf("Before reverse() => %s\n", sWord);
temp = reverse(sWord);
printf("After reverse() => %s\n", temp);
return 0;
}
char *reverse(char *word)
{
int i = 0;
int length = 0;
while(word[i] != '\0')
{
i++;
}
length = i;
char *temp_word = malloc(length * (sizeof(char)+1)); // +1 here.
for (i = 0; i < length; i++)
{
temp_word[i] = word[length - (i+1)];
//word[i] = temp_word[i]; <== Do not need this.
}
temp_word[length] = '\0';
return temp_word ;
}

expands shorthand notations like 1-3 in the string to array of strings in C

Lets say I have a string XYZ1-3.
I would like to convert it to a array of strings.
XYZ1,
XYZ2,
XYZ3.
is there an elegant way to do it in C?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **expand(const char *string, int *num){//num : out var
char *id = strdup(string);
int start, end, len;
sscanf(string, "%*[A-Z]%n%d-%d", &len, &start, &end);
id[len] = '\0';
*num = end-start+1;
char **array = malloc(*num * sizeof(char*));
for(int i=0;i < *num ;++i){
len = snprintf(NULL, 0, "%s%d", id, start + i);
array[i] = malloc(++len);
sprintf(array[i], "%s%d", id, start + i);
}
free(id);
return array;
}
int main(){
int n;
char **array = expand("XYZ1-3", &n);
for(int i=0;i<n;++i){
printf("%s\n", array[i]);
free(array[i]);
}
free(array);
return 0;
}
Allow the non-alphabetical(not A-Z) id part
#include <ctype.h>
int id_length(const char *string){
//return length of id part.
int i, len;
for(i=0;string[i];++i);
if(i==0)return 0;
for(i=i-1;isdigit(string[i]) && i>=0;--i);
if(string[i]!='-') return 0;//bad format
for(i=i-1;isdigit(string[i]) && i>=0;--i);
return i+1;
}
char **expand(const char *string, int *num){//num : out var
char *id = strdup(string);
int start, end, len;
len = id_length(string);
sscanf(string+len, "%d-%d", &start, &end);
id[len] = '\0';
*num = end-start+1;
char **array = malloc(*num * sizeof(char*));
for(int i=0;i < *num ;++i){
len = snprintf(NULL, 0, "%s%d", id, start + i);
array[i] = malloc(++len);
sprintf(array[i], "%s%d", id, start + i);
}
free(id);
return array;
}
Try this--
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
int len,i,c,d,p,j;
char arr[50];
char arr2[50];
char arr3[30][30];
char temp[30];
scanf("%s",arr);
len=strlen(arr);//calculating length of entire input
for(i=0;i<len;i++)
{
if(arr[i]!='-')
arr2[i]=arr[i];//arr2[] will hold the string without the numeral
else
break;
}
c=(int)arr[i-1]-48;//char is converted into int
d=(int)arr[i+1]-48;
for(i=0;i<len-3;i++)
temp[i]=arr2[i];
p=0;
for(i=c;i<=d;i++)
{
temp[len-3]=(char)(i+48);//int is converted into character
for(j=0;j<=len-3;j++)
arr3[p][j]=temp[j];//this 2d array holds array of strings
p++;
}
for(i=0;i<=(d-c);i++)
{
for(j=0;j<=len-3;j++)
{
printf("%c",arr3[i][j]);//printing the strings one by one
}
printf("\n");
}
getch();
}

Reverse characters word in array

for exemple i need to invers "Paris" to "siraP"...
My main:
int main(void)
{
char w1[] = "Paris";
ReverseWord(w1);
printf("The new word is: %s",w1);
return0;
}
and my function:
void ReverseWord(char *Str)
{
int counter=0;
for(int i=0; *(Str+i)!='\0'; i++)
counter++;
int length = counter-1;
char temp[length];
for(int j=0; temp[j]=='\0'; j++)
temp[j]=Str[length-j];
}
Now I have my renverse word in temp[].
I need to put it in my pointer *Str.
How can I do it??
Thanks
If you want use temp must then your function like this
void ReverseWord(char *Str)
{
int i,j;
if(str)
{
int length=strlen(Str);
char temp[length+1];
for( j=0; j<length; j++)
temp[j]=Str[length-1-j];
temp[j]='\0';
strcpy(Str,temp);
}
}
Without using temp as follows
void ReverseWord(char *Str)
{
int end= strlen(Str)-1;
int start = 0;
while( start<end )
{
Str[start] ^= Str[end];
Str[end] ^= Str[start];
Str[start]^= Str[end];
++start;
--end;
}
}
void ReverseWord(char *Str)
{
size_t len;
char temp, *end;
len = strlen(Str);
if (len < 2)
return;
end = Str + len - 1;
while (end > Str)
{
temp = *end;
*end-- = *Str;
*Str++ = temp;
}
}
One more option, this time with dangerous malloc(3).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *rev(char s[]) {
char *buf = (char *)malloc(sizeof(char) * strlen(s));
int i, j;
if(buf != NULL)
for(i = 0, j = strlen(s) - 1; j >= 0; i++, j--)
buf[i] = s[j];
return buf;
}
int main(int argc, char **argv) {
printf("%s\n", rev(argv[1]));
return 0;
}
Run with "foo bar foobar baz" and get zab raboof rab oof back:
~/tmp$ ./a.out "foo bar foobar baz"
zab raboof rab oof
Here I think you can study two algorithms:
C string length calculate: the end of the c string is '\0'
How to reverse a c string in place
And if you need to test the code, you should alloc testing strings in heap or strack. If you write a literal string, you may meet a bus error because of the literal string being saved in text-area which is a read only memory.
And the following is the demo:
#include <stdio.h>
#include <stdlib.h>
void reverse_string(char* str)
{
size_t len;
char tmp, *s;
//Get the length of string, in C the last char of one string is \0
for(s=str;*s;++s) ;
len = s - str;
//Here we use the algorithm for reverse the char inplace.
//We only need a char tmp place for swap each char
s = str + len - 1;
while(s>str){
tmp = *s;
*s = *str;
*str = tmp;
s--;
str++;
}
}
int main()
{
char* a = "abcd";
//Here "abcd" will be saved in READ Only Memory. If you test code, you will get a bus error.
char* b = (char*)calloc(1,10);
strcpy(b,a);
reverse_string(b);
printf("%s\n",b);
a = "abcde";
strcpy(b,a);
reverse_string(b);
printf("%s\n",b);
}
you can do it simply by following code
for(int k=0;k<strlen(temp);k++)
{
Str[k]=temp[k];
}

Trouble with argv and char

Since two hours, i'm trying to modify my program to give it arguments (argv) instead of a char.
So, here is my current code:
int i;
char ret[81];
*ret = 1;
for (i = 0; i < argc; i++)
{
ret[0] = '\0';
strcat(ret,argv[i]);
}
This code concatenate all args into a char, printf is returning the good same result as my old char argument, but not working in my code:
char test[] = "9...7....2...9..53.6..124..84...1.9.5.....8...31..4.....37..68..9..5.74147.......";
solve(test); //working
solve(ret); //not working
my app is launched like that:
./a.out "9...7...." "2...9..53" ".6..124.." "84...1.9." "5.....8.." ".31..4..." "..37..68." ".9..5.741" "47......."
Soooo, if anyone understand my problem i'll probably need some help :D
sample code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void solve(char *data){
static const char *result = "9...7....2...9..53.6..124..84...1.9.5.....8...31..4.....37..68..9..5.74147.......";
if(strcmp(result, data) == 0)
printf("working\n");
else
printf("not working\n");
}
int main(int argc, char *argv[]){
int i, total_length = 0;
for(i = 1; i < argc; ++i){
total_length += strlen(argv[i]);
}
char ret[total_length + 1];
ret[0] = '\0';
for(i = 1; i < argc; ++i){
strcat(ret, argv[i]);
}
char test[] = "9...7...."
"2...9..53"
".6..124.."
"84...1.9."
"5.....8.."
".31..4..."
"..37..68."
".9..5.741"
"47.......";
solve(test);
solve(ret);
return 0;
}

Concatenate all arguments (except the executable name)

Is there a C function that can concatenate all the passed arguments (except the name of the executable) into a char* and return it?
Try that:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
unsigned int i;
size_t len = 0;
char *_all_args, *all_args;
for(i=1; i<argc; i++) {
len += strlen(argv[i]);
}
_all_args = all_args = (char *)malloc(len+argc-1);
for(i=1; i<argc; i++) {
memcpy(_all_args, argv[i], strlen(argv[i]));
_all_args += strlen(argv[i])+1;
*(_all_args-1) = ' ';
}
*(_all_args-1) = 0;
printf("All %d args: '%s'\n", argc, all_args);
free(all_args);
return 0;
}
Why would there be ? Just use strcat in a loop.
Something like this? No guarantees that this will compile.
#include <string.h>
#include <stdio.h>
int main(int argc, char ** argv) {
int i;
int len = 1;
char * str;
for (i = 1; i < argc; i++) {
len += strlen(argv[i]);
}
str = malloc(sizeof(char)*len);
str[0] = '\0';
for (i = 1; i < argc; i++) {
strcat(str, argv[i]);
}
//Use str for whatever you want
printf("My string is %s\n", str);
free(str);
}
I don't think there's such a function, but if I'm not wrong, you just have to :
get the length : len = strlen(argv[1]) + strlen(argv[2]) + ... and check for overflow
use malloc : malloc(len + 1) * sizeof(char))
set your_copy[0] to '\0'
use strcat(your_copy, argv[1]), strcat(your_copy, argv[2])... for each remaining argv[]
EDIT : Oh, the previous answer may be better. ;)

Resources