2

私はCでプログラミングをほとんど行っていないということでこれを前置きしたいので、特定のソリューションが何であるかだけでなく、なぜ機能するのかを知りたいと思います。

パス名を取得し、同じディレクトリ内の別のファイルにパス名を返す関数を作成しようとしています。

  "/example/directory/with/image.png" => "/example/directory/with/thumbnail.png"

realpathand dirname(Linuxで作業しています。クロスプラットフォームに相当するものがある場合は、私に知らせてください)の使用例を読んだ後、私が試したことは次のとおりです。

#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

char *chop_path(char *orig) {
  char buf[PATH_MAX + 1];
  char *res, *dname, *thumb;

  res = realpath(orig, buf);
  if (res) {
    dname = dirname(res);
    thumb = strcat(dname, "/thumbnail.png");
    return thumb;
  }
  return 0;
}

それをコンパイルすることはうまくいくようですが、プログラムを実行する

int main(void) {
  char *res = chop_path("original.png");
  if (res) {
    printf("Resulting pathname: %s", res);
  } 
  return 0;
}

セグメンテーション違反が発生します。ヒントはありますか?

4

2 に答える 2

2

私が見る唯一の問題はあなたのchop_pathルーチンの署名です。そのはず

char *chop_path(char *orig) {

お使いのバージョンにがありません*。それは実際には大きな違いを生みます。がないと、引数文字列の最初の文字の文字コードを、パスの数値アドレス(つまり、へのポインタ)として*効果的に伝えdirnameて解釈することになります。realpathこれは、確実に割り当てていないメモリ不足の場所を指します。これを使おうとすると、「セグメンテーション違反」エラーが発生します。これは、事実上、許可されていないメモリに触れようとしていることを意味します。

もう1つの問題は、dirname()関数がで宣言されlibgen.hていることですが、これは含まれていませんでした。そのヘッダーを含めない場合、コンパイラーはポインターではなくdirname()戻り値を想定intし、64ビットアーキテクチャーでは、関数からの64ビットの戻り値が32ビットに切り詰められ、不正なポインターがに割り当てられますdname。それはあなたのセグメンテーション違反をすぐそこに引き起こすでしょう。

于 2012-04-30T03:29:13.890 に答える
1

dirname、、realpath不要な文字列バッファや文字列操作などを使用したくない場合は、次のようにすることができます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#define FILE_MAX 100

void chop_path(char path_name[], char new_file[]) {
    int len = strlen(path_name);
    int i;

    for (i=len-1; i>0 ; i--) {
        if (path_name[i] == '/') {
            strcpy(path_name+i+1, new_file);
            break;
        }   
    }   

    return;
}

int main(void) {
    char path[PATH_MAX + 1] = "/this/is/a/path/filename.c";
    char new_file[FILE_MAX] = "newfilename.txt";

    printf("old : %s \n", path);
    chop_path(path, new_file);
    printf("new : %s \n", path);

    return 0;
}

出力:

$ gcc path.c 
$ ./a.out 
old : /this/is/a/path/filename.c 
new : /this/is/a/path/newfilename.txt 
$ 
于 2012-04-30T03:51:29.183 に答える